-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
py/obj: Fix nan handling in REPR_C and REPR_D. #17531
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
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #17531 +/- ##
=======================================
Coverage 98.57% 98.57%
=======================================
Files 169 169
Lines 21968 21968
=======================================
Hits 21654 21654
Misses 314 314 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Code size report:
|
I ended up adding the REPR_C fix in the same PR as the impact on code footprint does not seems to be a problem on my ARMv4 platform, even when keeping the function inline. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for splitting this out into a separate PR.
For esp8266 it saves 16 bytes of code size!
But, 20 tests now fail on esp8266 😞
Here are the failing tests:
20 tests failed: basics/nanbox_smallint.py float/builtin_float_abs.py float/builtin_float_pow.py float/builtin_float_round.py float/bytearray_construct_endian.py float/bytes_construct_endian.py float/float1.py float/float2int_fp30_intbig.py float/float_divmod_relaxed.py float/float_parse.py float/float_struct.py float/float_struct_e.py float/inf_nan_arith.py float/math_domain.py float/math_domain_python311.py float/math_fun.py float/math_fun_bool.py float/math_fun_int.py float/string_format_fp30.py float/string_format_modulo.py
Eg the output of float/builtin_float_abs.py
is:
1.0 1.0
-1.0 1.0
0.0 2e-45
-0.0 2e-45
nan nan
-nan nan
inf nan
-inf nan
Lines 3 and 4 are wrong, they should be 0.0, but because bit 1 is not being cleared they are now very small numbers.
Lines 7 and 8 are wrong, they should be inf, but because bit 1 is not being cleared they are now nan.
So I don't think it's a good idea to drop the & ~3u
. I can understand the motivation (to round up some numbers), and it actually makes tests/misc/rge_sm.py
nearly pass now! That would be great, but I don't think this is the right approach.
(I did actually try something similar myself but instead in mp_obj_new_float()
I tried rounding up the 30-bit float by adding 0x04 if bit 1 was set in the original float. That gave quite good results, but I didn't get a chance to tidy that up for a PR yet.)
84b1918
to
5cb1af1
Compare
@dpgeorge Sorry for the first commit yesterday that failed so many tests. I did not immediately figure out how I could get a 32bit Linux build on Ubuntu 24.04 for easily running the full CI tests. I have now pushed a new version that fixes it, and takes your comments into account. |
It's now +44 bytes. That seems OK, considering it fixes a bug. Running the tests with ESP8266_GENERIC firmware, they are now all passing, including the modified |
Excellent, thank you !
I have been able to verify that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for updating, looks good now!
Tested again on esp8266 and the tests pass.
CPython math.nan is positive with regards to copysign. The signaling bit (aka sign flag) was incorrectly set. In addition, REPR_C and REPR_D should only use the _true_ nan to prevent system crash in case of hand-crafted floats. For instance, with REPR_C, any nan-like float following the pattern `01111111 1xxxxxxx xxxxxxxx xxxxx1xx` would be switched to an immediate object or a qstr string. When the qstr index is too large, this would cause a crash. This commit fixes the issue, and adds the relevant test cases. Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
Summary
CPython
math.nan
is positive with regards tomath.copysign()
.In MicroPython, this is only true with REPR_A and REPR_B.
In addition, REPR_C and REPR_D (nanbox) should only use the true
nan
to prevent system crash in case of hand-crafted floats.This problem has been discovered while working on a test code for #17444
Fixing the issue without changing the constant used for
math.nan
did break an existingcopysign
test case.Testing
A new test case has been added to specific test the behaviour of
math
constants with regard tocopysign
.Test cases creating special nans that were improperly interpreted in REPR_C have also been added.
Trade-offs and Alternatives
Fixing
nan
signaling flag does not change code size.The extra check in
mp_obj_new_float
will increase code size, butnanbox
platform is probably not very sensitive to larger code as it uses 64 bit objects. As the added code prevents a crash, it is probably worth the small size increase.mp_obj_float_get
). Indeed, leaving bit 1 provides a better estimation of the original float value than always biasing the result toward zero by clearing both low bits.