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:
Mark Dickinson 2012-04-29 15:31:56 +01:00
parent d68ac85e9a
commit e383e82e04
5 changed files with 102 additions and 5 deletions

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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)
{ {

View File

@ -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.