[3.14] gh-141042: fix sNaN's packing for mixed floating-point formats (GH-141107) (#141459)

gh-141042: fix sNaN's packing for mixed floating-point formats (GH-141107)
(cherry picked from commit 23d85a2a3f)

Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
This commit is contained in:
Miss Islington (bot) 2025-11-12 11:33:34 +01:00 committed by GitHub
parent 75b5157e84
commit e9c11b7495
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 59 additions and 14 deletions

View file

@ -2028,6 +2028,10 @@ PyFloat_Pack2(double x, char *data, int le)
memcpy(&v, &x, sizeof(v));
v &= 0xffc0000000000ULL;
bits = (unsigned short)(v >> 42); /* NaN's type & payload */
/* set qNaN if no payload */
if (!bits) {
bits |= (1<<9);
}
}
else {
sign = (x < 0.0);
@ -2200,16 +2204,16 @@ PyFloat_Pack4(double x, char *data, int le)
if ((v & (1ULL << 51)) == 0) {
uint32_t u32;
memcpy(&u32, &y, 4);
u32 &= ~(1 << 22); /* make sNaN */
/* if have payload, make sNaN */
if (u32 & 0x3fffff) {
u32 &= ~(1 << 22);
}
memcpy(&y, &u32, 4);
}
#else
uint32_t u32;
memcpy(&u32, &y, 4);
if ((v & (1ULL << 51)) == 0) {
u32 &= ~(1 << 22);
}
/* Workaround RISC-V: "If a NaN value is converted to a
* different floating-point type, the result is the
* canonical NaN of the new type". The canonical NaN here
@ -2220,6 +2224,10 @@ PyFloat_Pack4(double x, char *data, int le)
/* add payload */
u32 -= (u32 & 0x3fffff);
u32 += (uint32_t)((v & 0x7ffffffffffffULL) >> 29);
/* if have payload, make sNaN */
if ((v & (1ULL << 51)) == 0 && (u32 & 0x3fffff)) {
u32 &= ~(1 << 22);
}
memcpy(&y, &u32, 4);
#endif