From 4e0a6755f8be98336c088e8bd850f85457fbf704 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Tue, 4 Mar 2025 09:51:05 +0000 Subject: [PATCH] new `ExpInt` class --- mmgen/util2.py | 32 ++++++++++++++++++++++++++++++++ test/modtest_d/ut_misc.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/mmgen/util2.py b/mmgen/util2.py index 31efe1af..cc0700d9 100755 --- a/mmgen/util2.py +++ b/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 diff --git a/test/modtest_d/ut_misc.py b/test/modtest_d/ut_misc.py index f77f2b10..81c7e0ca 100755 --- a/test/modtest_d/ut_misc.py +++ b/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