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').
This commit is contained in:
parent
d68ac85e9a
commit
e383e82e04
|
@ -8,6 +8,8 @@ PyAPI_FUNC(double) _Py_dg_strtod(const char *str, char **ptr);
|
||||||
PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits,
|
PyAPI_FUNC(char *) _Py_dg_dtoa(double d, int mode, int ndigits,
|
||||||
int *decpt, int *sign, char **rve);
|
int *decpt, int *sign, char **rve);
|
||||||
PyAPI_FUNC(void) _Py_dg_freedtoa(char *s);
|
PyAPI_FUNC(void) _Py_dg_freedtoa(char *s);
|
||||||
|
PyAPI_FUNC(double) _Py_dg_stdnan(int sign);
|
||||||
|
PyAPI_FUNC(double) _Py_dg_infinity(int sign);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -870,6 +870,19 @@ class InfNanTest(unittest.TestCase):
|
||||||
self.assertFalse(NAN.is_inf())
|
self.assertFalse(NAN.is_inf())
|
||||||
self.assertFalse((0.).is_inf())
|
self.assertFalse((0.).is_inf())
|
||||||
|
|
||||||
|
def test_inf_signs(self):
|
||||||
|
self.assertEqual(copysign(1.0, float('inf')), 1.0)
|
||||||
|
self.assertEqual(copysign(1.0, float('-inf')), -1.0)
|
||||||
|
|
||||||
|
@unittest.skipUnless(getattr(sys, 'float_repr_style', '') == 'short',
|
||||||
|
"applies only when using short float repr style")
|
||||||
|
def test_nan_signs(self):
|
||||||
|
# When using the dtoa.c code, the sign of float('nan') should
|
||||||
|
# be predictable.
|
||||||
|
self.assertEqual(copysign(1.0, float('nan')), 1.0)
|
||||||
|
self.assertEqual(copysign(1.0, float('-nan')), -1.0)
|
||||||
|
|
||||||
|
|
||||||
fromHex = float.fromhex
|
fromHex = float.fromhex
|
||||||
toHex = float.hex
|
toHex = float.hex
|
||||||
class HexFloatTestCase(unittest.TestCase):
|
class HexFloatTestCase(unittest.TestCase):
|
||||||
|
|
|
@ -10,6 +10,9 @@ What's New in Python 3.3.0 Alpha 3?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #14521: Make result of float('nan') and float('-nan') more
|
||||||
|
consistent across platforms.
|
||||||
|
|
||||||
- Issue #14646: __import__() sets __loader__ if the loader did not.
|
- Issue #14646: __import__() sets __loader__ if the loader did not.
|
||||||
|
|
||||||
- Issue #14605: No longer have implicit entries in sys.meta_path. If
|
- Issue #14605: No longer have implicit entries in sys.meta_path. If
|
||||||
|
|
|
@ -265,6 +265,16 @@ typedef union { double d; ULong L[2]; } U;
|
||||||
#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
|
#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
|
||||||
#define Big1 0xffffffff
|
#define Big1 0xffffffff
|
||||||
|
|
||||||
|
/* Standard NaN used by _Py_dg_stdnan. */
|
||||||
|
|
||||||
|
#define NAN_WORD0 0x7ff80000
|
||||||
|
#define NAN_WORD1 0
|
||||||
|
|
||||||
|
/* Bits of the representation of positive infinity. */
|
||||||
|
|
||||||
|
#define POSINF_WORD0 0x7ff00000
|
||||||
|
#define POSINF_WORD1 0
|
||||||
|
|
||||||
/* struct BCinfo is used to pass information from _Py_dg_strtod to bigcomp */
|
/* struct BCinfo is used to pass information from _Py_dg_strtod to bigcomp */
|
||||||
|
|
||||||
typedef struct BCinfo BCinfo;
|
typedef struct BCinfo BCinfo;
|
||||||
|
@ -1486,6 +1496,36 @@ bigcomp(U *rv, const char *s0, BCinfo *bc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a 'standard' NaN value.
|
||||||
|
|
||||||
|
There are exactly two quiet NaNs that don't arise by 'quieting' signaling
|
||||||
|
NaNs (see IEEE 754-2008, section 6.2.1). If sign == 0, return the one whose
|
||||||
|
sign bit is cleared. Otherwise, return the one whose sign bit is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
double
|
||||||
|
_Py_dg_stdnan(int sign)
|
||||||
|
{
|
||||||
|
U rv;
|
||||||
|
word0(&rv) = NAN_WORD0;
|
||||||
|
word1(&rv) = NAN_WORD1;
|
||||||
|
if (sign)
|
||||||
|
word0(&rv) |= Sign_bit;
|
||||||
|
return dval(&rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return positive or negative infinity, according to the given sign (0 for
|
||||||
|
* positive infinity, 1 for negative infinity). */
|
||||||
|
|
||||||
|
double
|
||||||
|
_Py_dg_infinity(int sign)
|
||||||
|
{
|
||||||
|
U rv;
|
||||||
|
word0(&rv) = POSINF_WORD0;
|
||||||
|
word1(&rv) = POSINF_WORD1;
|
||||||
|
return sign ? -dval(&rv) : dval(&rv);
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
_Py_dg_strtod(const char *s00, char **se)
|
_Py_dg_strtod(const char *s00, char **se)
|
||||||
{
|
{
|
||||||
|
@ -1886,20 +1926,20 @@ _Py_dg_strtod(const char *s00, char **se)
|
||||||
bd2++;
|
bd2++;
|
||||||
|
|
||||||
/* At this stage bd5 - bb5 == e == bd2 - bb2 + bbe, bb2 - bs2 == 1,
|
/* At this stage bd5 - bb5 == e == bd2 - bb2 + bbe, bb2 - bs2 == 1,
|
||||||
and bs == 1, so:
|
and bs == 1, so:
|
||||||
|
|
||||||
tdv == bd * 10**e = bd * 2**(bbe - bb2 + bd2) * 5**(bd5 - bb5)
|
tdv == bd * 10**e = bd * 2**(bbe - bb2 + bd2) * 5**(bd5 - bb5)
|
||||||
srv == bb * 2**bbe = bb * 2**(bbe - bb2 + bb2)
|
srv == bb * 2**bbe = bb * 2**(bbe - bb2 + bb2)
|
||||||
0.5 ulp(srv) == 2**(bbe-1) = bs * 2**(bbe - bb2 + bs2)
|
0.5 ulp(srv) == 2**(bbe-1) = bs * 2**(bbe - bb2 + bs2)
|
||||||
|
|
||||||
It follows that:
|
It follows that:
|
||||||
|
|
||||||
M * tdv = bd * 2**bd2 * 5**bd5
|
M * tdv = bd * 2**bd2 * 5**bd5
|
||||||
M * srv = bb * 2**bb2 * 5**bb5
|
M * srv = bb * 2**bb2 * 5**bb5
|
||||||
M * 0.5 ulp(srv) = bs * 2**bs2 * 5**bb5
|
M * 0.5 ulp(srv) = bs * 2**bs2 * 5**bb5
|
||||||
|
|
||||||
for some constant M. (Actually, M == 2**(bb2 - bbe) * 5**bb5, but
|
for some constant M. (Actually, M == 2**(bb2 - bbe) * 5**bb5, but
|
||||||
this fact is not needed below.)
|
this fact is not needed below.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Remove factor of 2**i, where i = min(bb2, bd2, bs2). */
|
/* Remove factor of 2**i, where i = min(bb2, bd2, bs2). */
|
||||||
|
|
|
@ -22,6 +22,43 @@ case_insensitive_match(const char *s, const char *t)
|
||||||
the successfully parsed portion of the string. On failure, return -1.0 and
|
the successfully parsed portion of the string. On failure, return -1.0 and
|
||||||
set *endptr to point to the start of the string. */
|
set *endptr to point to the start of the string. */
|
||||||
|
|
||||||
|
#ifndef PY_NO_SHORT_FLOAT_REPR
|
||||||
|
|
||||||
|
double
|
||||||
|
_Py_parse_inf_or_nan(const char *p, char **endptr)
|
||||||
|
{
|
||||||
|
double retval;
|
||||||
|
const char *s;
|
||||||
|
int negate = 0;
|
||||||
|
|
||||||
|
s = p;
|
||||||
|
if (*s == '-') {
|
||||||
|
negate = 1;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
else if (*s == '+') {
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if (case_insensitive_match(s, "inf")) {
|
||||||
|
s += 3;
|
||||||
|
if (case_insensitive_match(s, "inity"))
|
||||||
|
s += 5;
|
||||||
|
retval = _Py_dg_infinity(negate);
|
||||||
|
}
|
||||||
|
else if (case_insensitive_match(s, "nan")) {
|
||||||
|
s += 3;
|
||||||
|
retval = _Py_dg_stdnan(negate);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s = p;
|
||||||
|
retval = -1.0;
|
||||||
|
}
|
||||||
|
*endptr = (char *)s;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
double
|
double
|
||||||
_Py_parse_inf_or_nan(const char *p, char **endptr)
|
_Py_parse_inf_or_nan(const char *p, char **endptr)
|
||||||
{
|
{
|
||||||
|
@ -57,6 +94,8 @@ _Py_parse_inf_or_nan(const char *p, char **endptr)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _PyOS_ascii_strtod:
|
* _PyOS_ascii_strtod:
|
||||||
* @nptr: the string to convert to a numeric value.
|
* @nptr: the string to convert to a numeric value.
|
||||||
|
|
Loading…
Reference in New Issue