new ExpInt class

This commit is contained in:
The MMGen Project 2025-03-04 09:51:05 +00:00
commit 4e0a6755f8
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
2 changed files with 70 additions and 0 deletions

View file

@ -196,3 +196,35 @@ def decode_pretty_hexdump(data):
except:
msg('Data not in hexdump format')
return False
class ExpInt(int):
'encode or parse an integer in exponential notation with specified precision'
max_prec = 10
def __new__(cls, spec, *, prec):
assert 0 < prec < cls.max_prec
cls.prec = prec
from .util import is_int
if is_int(spec):
return int.__new__(cls, spec)
else:
assert isinstance(spec, str), f'ExpInt: {spec!r}: not a string!'
assert len(spec) >= 3, f'ExpInt: {spec!r}: invalid specifier'
val, exp = spec.split('e')
assert is_int(val) and is_int(exp)
return int.__new__(cls, val + '0' * int(exp))
@property
def trunc(self):
s = str(self)
return int(s[:self.prec] + '0' * (len(s) - self.prec))
@property
def enc(self):
s = str(self)
s_len = len(s)
digits = s[:min(s_len, self.prec)].rstrip('0')
ret = '{}e{}'.format(digits, s_len - len(digits))
return ret if len(ret) < s_len else s

View file

@ -154,3 +154,41 @@ class unit_tests:
assert '4.3' == ver['4.3'] == '4.3'
return True
def exp_int(self, name, ut, desc='ExpInt() class'):
from mmgen.util2 import ExpInt
for num, trunc, chk, out in (
('0e0', 0, 0, '0'),
('0e1', 0, 0, '0'),
('3e0', 3, 3, '3'),
('3e1', 30, 30, '30'),
('3e2', 300, 300, '300'),
('3e3', 3000, 3000, '3e3'),
(3000, 3000, 3000, '3e3'),
(1, 1, 1, '1'),
('123e0', 123, 123, '123'),
(123, 123, 123, '123'),
(12345, 12340, 12345, '12345'),
(123456, 123400, 123456, '123456'),
(1234567, 1234000, 1234000, '1234e3'),
(123456789, 123400000, 123400000, '1234e5'),
(998877665544332211, 998800000000000000, 998800000000000000, '9988e14'),
):
e = ExpInt(num, prec=4)
enc = e.enc
assert enc == out, f'{enc} != {out}'
assert e.trunc == trunc, f'{e.trunc} != {trunc}'
vmsg('')
vmsg(f'num {num}')
vmsg(f'enc {enc}')
dec = ExpInt(enc, prec=4)
vmsg(f'enc -> dec {dec}')
vmsg(f'chk {chk}')
assert dec == chk, f'{dec} != {chk}'
dec_enc = dec.enc
vmsg(f'dec -> enc {dec_enc}')
vmsg(f'out {out}')
assert dec_enc == out, f'{dec_enc} != {out}'
return True