Skip to content

py/obj: Improve REPR_C accuracy and include it in CI tests #17731

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions ports/unix/variants/longlong/mpconfigvariant.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@

#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG)

// We build it on top of REPR C, which uses memory-efficient floating point
// objects encoded directly mp_obj_t (30 bits only).
// Therefore this variant should be built using MICROPY_FORCE_32BIT=1

#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
typedef int mp_int_t;
typedef unsigned int mp_uint_t;

// Set base feature level.
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)

Expand Down
4 changes: 4 additions & 0 deletions py/obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
mp_float_t f;
mp_uint_t u;
} num = {.u = ((mp_uint_t)o - 0x80800000u) & ~3u};
// Rather than always truncating toward zero, which creates a strong
// bias, copy the two previous bits to fill in the two missing bits.
// This appears to be a pretty good heuristic.
num.u |= (num.u >> 2) & 3u;
return num.f;
}
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
Expand Down
3 changes: 3 additions & 0 deletions tests/float/cmath_fun.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
print("%.5g" % ret)
elif type(ret) == tuple:
print("%.5g %.5g" % ret)
elif f_name == "exp":
# exp amplifies REPR_C inaccuracies, so we need to check one digit less
print("complex(%.4g, %.4g)" % (real, ret.imag))
else:
# some test (eg cmath.sqrt(-0.5)) disagree with CPython with tiny real part
real = ret.real
Expand Down
5 changes: 5 additions & 0 deletions tests/float/math_fun_special.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,15 @@
("lgamma", lgamma, pos_test_values + [50.0, 100.0]),
]

is_REPR_C = float("1.0000001") == float("1.0")

for function_name, function, test_vals in functions:
for value in test_vals:
try:
ans = "{:.4g}".format(function(value))
except ValueError as e:
ans = str(e)
# a tiny error in REPR_C value for 1.5204998778 causes a wrong rounded value
if is_REPR_C and function_name == 'erfc' and ans == "1.521":
ans = "1.52"
print("{}({:.4g}) = {}".format(function_name, value, ans))
42 changes: 0 additions & 42 deletions tests/float/string_format_fp30.py

This file was deleted.

10 changes: 9 additions & 1 deletion tests/misc/rge_sm.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def phaseDiagram(system, trajStart, trajPlot, h=0.1, tend=1.0, range=1.0):


def singleTraj(system, trajStart, h=0.02, tend=1.0):
is_REPR_C = float("1.0000001") == float("1.0")
tstart = 0.0

# compute the trajectory
Expand All @@ -130,7 +131,14 @@ def singleTraj(system, trajStart, h=0.02, tend=1.0):

for i in range(len(rk.Trajectory)):
tr = rk.Trajectory[i]
print(" ".join(["{:.4f}".format(t) for t in tr]))
tr_str = " ".join(["{:.4f}".format(t) for t in tr])
if is_REPR_C:
# allow two small deviations for REPR_C
if tr_str == "1.0000 0.3559 0.6485 1.1944 0.9271 0.1083":
tr_str = "1.0000 0.3559 0.6485 1.1944 0.9272 0.1083"
if tr_str == "16.0000 0.3894 0.5793 0.7017 0.5686 -0.0168":
tr_str = "16.0000 0.3894 0.5793 0.7017 0.5686 -0.0167"
print(tr_str)


# phaseDiagram(sysSM, (lambda i, j: [0.354, 0.654, 1.278, 0.8 + 0.2 * i, 0.1 + 0.1 * j]), (lambda a: (a[4], a[5])), h=0.1, tend=math.log(10**17))
Expand Down
2 changes: 1 addition & 1 deletion tests/perf_bench/bm_fft.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def reverse(x, bits):

# Initialization
n = len(vector)
levels = int(math.log(n) / math.log(2))
levels = int(round(math.log(n) / math.log(2)))
coef = (2 if inverse else -2) * cmath.pi / n
exptable = [cmath.rect(1, i * coef) for i in range(n // 2)]
vector = [vector[reverse(i, levels)] for i in range(n)] # Copy with bit-reversed permutation
Expand Down
6 changes: 0 additions & 6 deletions tests/run-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,6 @@ def open(self, path, mode):
# Tests to skip on specific targets.
# These are tests that are difficult to detect that they should not be run on the given target.
platform_tests_to_skip = {
"esp8266": (
"misc/rge_sm.py", # incorrect values due to object representation C
),
"minimal": (
"basics/class_inplace_op.py", # all special methods not supported
"basics/subclass_native_init.py", # native subclassing corner cases not support
Expand Down Expand Up @@ -788,9 +785,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
skip_tests.add(
"float/float2int_intbig.py"
) # requires fp32, there's float2int_fp30_intbig.py instead
skip_tests.add(
"float/string_format.py"
) # requires fp32, there's string_format_fp30.py instead
skip_tests.add("float/bytes_construct.py") # requires fp32
skip_tests.add("float/bytearray_construct.py") # requires fp32
skip_tests.add("float/float_format_ints_power10.py") # requires fp32
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy