Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e383e82

Browse files
committed
Issue #14521: Make result of float('nan') and float('-nan') more consistent across platforms. Further, don't rely on Py_HUGE_VAL for float('inf').
1 parent d68ac85 commit e383e82

5 files changed

Lines changed: 102 additions & 5 deletions

File tree

Include/dtoa.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ PyAPI_FUNC(double) _Py_dg_strtod(const char *str, char **ptr);
88
PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits,
99
int *decpt, int *sign, char **rve);
1010
PyAPI_FUNC(void) _Py_dg_freedtoa(char *s);
11+
PyAPI_FUNC(double) _Py_dg_stdnan(int sign);
12+
PyAPI_FUNC(double) _Py_dg_infinity(int sign);
1113

1214

1315
#ifdef __cplusplus

Lib/test/test_float.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,19 @@ def notest_float_inf(self):
870870
self.assertFalse(NAN.is_inf())
871871
self.assertFalse((0.).is_inf())
872872

873+
def test_inf_signs(self):
874+
self.assertEqual(copysign(1.0, float('inf')), 1.0)
875+
self.assertEqual(copysign(1.0, float('-inf')), -1.0)
876+
877+
@unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
878+
"applies only when using short float repr style")
879+
def test_nan_signs(self):
880+
# When using the dtoa.c code, the sign of float('nan') should
881+
# be predictable.
882+
self.assertEqual(copysign(1.0, float('nan')), 1.0)
883+
self.assertEqual(copysign(1.0, float('-nan')), -1.0)
884+
885+
873886
fromHex = float.fromhex
874887
toHex = float.hex
875888
class HexFloatTestCase(unittest.TestCase):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.3.0 Alpha 3?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #14521: Make result of float('nan') and float('-nan') more
14+
consistent across platforms.
15+
1316
- Issue #14646: __import__() sets __loader__ if the loader did not.
1417

1518
- Issue #14605: No longer have implicit entries in sys.meta_path. If

Python/dtoa.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,16 @@ typedef union { double d; ULong L[2]; } U;
265265
#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
266266
#define Big1 0xffffffff
267267

268+
/* Standard NaN used by _Py_dg_stdnan. */
269+
270+
#define NAN_WORD0 0x7ff80000
271+
#define NAN_WORD1 0
272+
273+
/* Bits of the representation of positive infinity. */
274+
275+
#define POSINF_WORD0 0x7ff00000
276+
#define POSINF_WORD1 0
277+
268278
/* struct BCinfo is used to pass information from _Py_dg_strtod to bigcomp */
269279

270280
typedef struct BCinfo BCinfo;
@@ -1486,6 +1496,36 @@ bigcomp(U *rv, const char *s0, BCinfo *bc)
14861496
return 0;
14871497
}
14881498

1499+
/* Return a 'standard' NaN value.
1500+
1501+
There are exactly two quiet NaNs that don't arise by 'quieting' signaling
1502+
NaNs (see IEEE 754-2008, section 6.2.1). If sign == 0, return the one whose
1503+
sign bit is cleared. Otherwise, return the one whose sign bit is set.
1504+
*/
1505+
1506+
double
1507+
_Py_dg_stdnan(int sign)
1508+
{
1509+
U rv;
1510+
word0(&rv) = NAN_WORD0;
1511+
word1(&rv) = NAN_WORD1;
1512+
if (sign)
1513+
word0(&rv) |= Sign_bit;
1514+
return dval(&rv);
1515+
}
1516+
1517+
/* Return positive or negative infinity, according to the given sign (0 for
1518+
* positive infinity, 1 for negative infinity). */
1519+
1520+
double
1521+
_Py_dg_infinity(int sign)
1522+
{
1523+
U rv;
1524+
word0(&rv) = POSINF_WORD0;
1525+
word1(&rv) = POSINF_WORD1;
1526+
return sign ? -dval(&rv) : dval(&rv);
1527+
}
1528+
14891529
double
14901530
_Py_dg_strtod(const char *s00, char **se)
14911531
{
@@ -1886,20 +1926,20 @@ _Py_dg_strtod(const char *s00, char **se)
18861926
bd2++;
18871927

18881928
/* At this stage bd5 - bb5 == e == bd2 - bb2 + bbe, bb2 - bs2 == 1,
1889-
and bs == 1, so:
1929+
and bs == 1, so:
18901930
18911931
tdv == bd * 10**e = bd * 2**(bbe - bb2 + bd2) * 5**(bd5 - bb5)
18921932
srv == bb * 2**bbe = bb * 2**(bbe - bb2 + bb2)
1893-
0.5 ulp(srv) == 2**(bbe-1) = bs * 2**(bbe - bb2 + bs2)
1933+
0.5 ulp(srv) == 2**(bbe-1) = bs * 2**(bbe - bb2 + bs2)
18941934
1895-
It follows that:
1935+
It follows that:
18961936
18971937
M * tdv = bd * 2**bd2 * 5**bd5
18981938
M * srv = bb * 2**bb2 * 5**bb5
18991939
M * 0.5 ulp(srv) = bs * 2**bs2 * 5**bb5
19001940
1901-
for some constant M. (Actually, M == 2**(bb2 - bbe) * 5**bb5, but
1902-
this fact is not needed below.)
1941+
for some constant M. (Actually, M == 2**(bb2 - bbe) * 5**bb5, but
1942+
this fact is not needed below.)
19031943
*/
19041944

19051945
/* Remove factor of 2**i, where i = min(bb2, bd2, bs2). */

Python/pystrtod.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,43 @@ case_insensitive_match(const char *s, const char *t)
2222
the successfully parsed portion of the string. On failure, return -1.0 and
2323
set *endptr to point to the start of the string. */
2424

25+
#ifndef PY_NO_SHORT_FLOAT_REPR
26+
27+
double
28+
_Py_parse_inf_or_nan(const char *p, char **endptr)
29+
{
30+
double retval;
31+
const char *s;
32+
int negate = 0;
33+
34+
s = p;
35+
if (*s == '-') {
36+
negate = 1;
37+
s++;
38+
}
39+
else if (*s == '+') {
40+
s++;
41+
}
42+
if (case_insensitive_match(s, "inf")) {
43+
s += 3;
44+
if (case_insensitive_match(s, "inity"))
45+
s += 5;
46+
retval = _Py_dg_infinity(negate);
47+
}
48+
else if (case_insensitive_match(s, "nan")) {
49+
s += 3;
50+
retval = _Py_dg_stdnan(negate);
51+
}
52+
else {
53+
s = p;
54+
retval = -1.0;
55+
}
56+
*endptr = (char *)s;
57+
return retval;
58+
}
59+
60+
#else
61+
2562
double
2663
_Py_parse_inf_or_nan(const char *p, char **endptr)
2764
{
@@ -57,6 +94,8 @@ _Py_parse_inf_or_nan(const char *p, char **endptr)
5794
return retval;
5895
}
5996

97+
#endif
98+
6099
/**
61100
* _PyOS_ascii_strtod:
62101
* @nptr: the string to convert to a numeric value.

0 commit comments

Comments
 (0)