summaryrefslogtreecommitdiff
path: root/tests/float/float_struct_e_doubleprec.py
diff options
context:
space:
mode:
authorYoctopuce dev <dev@yoctopuce.com>2025-06-06 14:55:21 +0200
committerDamien George <damien@micropython.org>2025-08-01 00:47:33 +1000
commitdbbaa959c85c04dbbcde5908b5d0775b574e44e7 (patch)
tree050bd1670b061788d291c0d88af22a6aad722f64 /tests/float/float_struct_e_doubleprec.py
parente4e1c9f4132f839dac0291557d9b992f67577fd3 (diff)
py/formatfloat: Improve accuracy of float formatting code.
Following discussions in PR #16666, this commit updates the float formatting code to improve the `repr` reversibility, i.e. the percentage of valid floating point numbers that do parse back to the same number when formatted by `repr` (in CPython it's 100%). This new code offers a choice of 3 float conversion methods, depending on the desired tradeoff between code size and conversion precision: - BASIC method is the smallest code footprint - APPROX method uses an iterative method to approximate the exact representation, which is a bit slower but but does not have a big impact on code size. It provides `repr` reversibility on >99.8% of the cases in double precision, and on >98.5% in single precision (except with REPR_C, where reversibility is 100% as the last two bits are not taken into account). - EXACT method uses higher-precision floats during conversion, which provides perfect results but has a higher impact on code size. It is faster than APPROX method, and faster than the CPython equivalent implementation. It is however not available on all compilers when using FLOAT_IMPL_DOUBLE. Here is the table comparing the impact of the three conversion methods on code footprint on PYBV10 (using single-precision floats) and reversibility rate for both single-precision and double-precision floats. The table includes current situation as a baseline for the comparison: PYBV10 REPR_C FLOAT DOUBLE current = 364688 12.9% 27.6% 37.9% basic = 364812 85.6% 60.5% 85.7% approx = 365080 100.0% 98.5% 99.8% exact = 366408 100.0% 100.0% 100.0% Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
Diffstat (limited to 'tests/float/float_struct_e_doubleprec.py')
-rw-r--r--tests/float/float_struct_e_doubleprec.py43
1 files changed, 43 insertions, 0 deletions
diff --git a/tests/float/float_struct_e_doubleprec.py b/tests/float/float_struct_e_doubleprec.py
new file mode 100644
index 000000000..403fbc5db
--- /dev/null
+++ b/tests/float/float_struct_e_doubleprec.py
@@ -0,0 +1,43 @@
+# Test struct pack/unpack with 'e' typecode.
+
+try:
+ import struct
+except ImportError:
+ print("SKIP")
+ raise SystemExit
+
+test_values = (
+ 1e-7,
+ 2e-7,
+ 1e-6,
+ 1e-5,
+ 1e-4,
+ 1e-3,
+ 1e-2,
+ 0.1,
+ 0,
+ 1,
+ 2,
+ 4,
+ 8,
+ 10,
+ 100,
+ 1e3,
+ 1e4,
+ 6e4,
+ float("inf"),
+)
+
+for j in test_values:
+ for i in (j, -j):
+ x = struct.pack("<e", i)
+ v = struct.unpack("<e", x)[0]
+ print("%.7f %s %.15f %s" % (i, x, v, i == v))
+
+# In CPython, packing a float that doesn't fit into a half-float raises OverflowError.
+# But in MicroPython it does not, but rather stores the value as inf.
+# This test is here for coverage.
+try:
+ struct.pack("e", 1e15)
+except OverflowError:
+ pass