Browse Source

new `ExpInt` class

The MMGen Project 1 week ago
parent
commit
4e0a6755f8
2 changed files with 70 additions and 0 deletions
  1. 32 0
      mmgen/util2.py
  2. 38 0
      test/modtest_d/ut_misc.py

+ 32 - 0
mmgen/util2.py

@@ -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

+ 38 - 0
test/modtest_d/ut_misc.py

@@ -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