Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
gh-130317: fix PyFloat_Pack/Unpack[24] for NaN's with payload#130452
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
Uh oh!
There was an error while loading. Please reload this page.
Conversation
skirpichev commented Feb 22, 2025 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
7da9a1f to a6e99f9Comparea6e99f9 to 971fd98Compare This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as outdated.
This comment was marked as outdated.
139501d to e6c1c12Compareskirpichev commented Feb 25, 2025
Ok, I've added new tests in test_capi.test_floats (in principle, test_struct's tests are redundant). win32 behavior (you can't unset "quiet" bit for NaN) looks as a bug for me. |
Uh oh!
There was an error while loading. Please reload this page.
vstinner commented Feb 25, 2025
Any idea why there is a bug only on Windows? |
skirpichev commented Feb 25, 2025
Only on win32. Though, I suspect the situation could be worse. Maybe I should revert win32-workaround and test this with some buildbots? C17 says: "This specification does not define the behavior of signaling NaNs." But I don't think this means you can't flip appropriate bit in float/double to make a signaling NaN. |
skirpichev commented Apr 27, 2025
Ok, I think it's ready for review. Test for Windows failed in 32-bit mode (signaling NaN type not preserved in roundtrip), that seems to be a known issue: https://developercommunity.visualstudio.com/t/155064 (sNaN returned from function becomes qNaN). See also https://developercommunity.visualstudio.com/t/903305 and https://en.delphipraxis.net/topic/12198-delphi-win32-quiets-signaling-nan-on-function-return/. In principle, it's possible to workaround this for the struct module. But not for C-API ( |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Victor Stinner <vstinner@python.org>
vstinner left a comment
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.
LGTM. I just have some minor comments.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| deftest_pack_unpack_roundtrip_for_nans(self): | ||
| pack=_testcapi.float_pack | ||
| unpack=_testcapi.float_unpack | ||
| for_inrange(1000): |
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.
100 tests should be enough to validate the implementation, no?
| for_inrange(1000): | |
| for_inrange(100): |
1000 tests might be a little bit too slow, I don't think that it's worth it.
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.
Up to you, the test looks instantaneous on my system. 0.3sec vs 0.03. Where the threshold?
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.
I don't think speed is really an issue here, but having the potential for 6000 failed test reports seems like major overkill. I think 10 would actually be plenty for this loop.
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Victor Stinner <vstinner@python.org>
6157135 into python:mainUh oh!
There was an error while loading. Please reload this page.
vstinner commented Apr 28, 2025
Merged, thank you. |
vstinner commented Apr 28, 2025
Should we backport this change? It's unclear to me if it's a new feature or a bugfix. The issue is reported as a bug report. |
skirpichev commented Apr 28, 2025
Strictly speaking, it's a bug, though maybe a very minor one (that's why there was no label for 3.13 backport). From IEEE 754 (2008), 6.2.3: "Conversion of a quiet NaN from a narrower format to a wider format in the same radix, and then back to the same narrower format, should not change the quiet NaN payload in any way except to make it canonical." E.g. in C nan's payload is preserved in conversions (e.g. float->double) or partially preserved (e.g. double -> float). |
vstinner commented Apr 29, 2025
test_capi.test_float fails on x86 Debian Installed with X 3.x: https://buildbot.python.org/#/builders/1244/builds/5176 test.pythoninfo: There are failures on 16, 32 and 64 bit floats (size: 2, 4, 8). Examples: |
vstinner commented Apr 29, 2025
I can reproduce the issue on Fedora 42 by building Python using |
skirpichev commented Apr 29, 2025
Hmm, again in all cases sNaN seems transformed to qNaN. I think underlying reason is same and we should apply workaround for 32-bit modes. |
vstinner commented Apr 29, 2025
I replaced |
vstinner commented Apr 29, 2025
Aha, just copying a double to another double clears the sNaN flag: d is not equal to ob_fval. |
vstinner commented Apr 29, 2025
The sNaN flag is easily lost. I added some debug of the uint64_t value in different functions. Between float_pack() and PyFloat_Pack4(), the sNaN flag is lost: PyFloat_Pack4() is called with the wrong value :-( |
skirpichev commented Apr 29, 2025
Hmm, indeed. I should finally do memcpy() to created PyFloat's ob_fval, then return it. Does it work: ? |
vstinner commented Apr 29, 2025
I wrote #133150 to fix 3 bugs, but it's not enough to fix the test on x86. |
vstinner commented May 5, 2025
Tests were fixed by #133204. |
Previously (1) all NaN's payload in PyFloat_Pack/Unpack2() was ignored and (2) type conversions (float <-> double) in PyFloat_Pack/Unpack4() broke pack-unpack round-trip for sNaN's.
nanfloats is non-invertible #130317