mirror of https://github.com/python/cpython
gh-104263: Rely on Py_NAN and introduce Py_INFINITY (GH-104202)
This PR removes `_Py_dg_stdnan` and `_Py_dg_infinity` in favour of using the standard `NAN` and `INFINITY` macros provided by C99. This change has the side-effect of fixing a bug on MIPS where the hard-coded value used by `_Py_dg_stdnan` gave a signalling NaN rather than a quiet NaN. --------- Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
This commit is contained in:
parent
a7a2dbbf72
commit
7a3b03509e
|
@ -64,8 +64,6 @@ 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);
|
|
||||||
|
|
||||||
#endif // _PY_SHORT_FLOAT_REPR == 1
|
#endif // _PY_SHORT_FLOAT_REPR == 1
|
||||||
|
|
||||||
|
|
|
@ -39,27 +39,24 @@
|
||||||
// Return 1 if float or double arg is neither infinite nor NAN, else 0.
|
// Return 1 if float or double arg is neither infinite nor NAN, else 0.
|
||||||
#define Py_IS_FINITE(X) isfinite(X)
|
#define Py_IS_FINITE(X) isfinite(X)
|
||||||
|
|
||||||
/* HUGE_VAL is supposed to expand to a positive double infinity. Python
|
// Py_INFINITY: Value that evaluates to a positive double infinity.
|
||||||
* uses Py_HUGE_VAL instead because some platforms are broken in this
|
#ifndef Py_INFINITY
|
||||||
* respect. We used to embed code in pyport.h to try to worm around that,
|
# define Py_INFINITY ((double)INFINITY)
|
||||||
* but different platforms are broken in conflicting ways. If you're on
|
#endif
|
||||||
* a platform where HUGE_VAL is defined incorrectly, fiddle your Python
|
|
||||||
* config to #define Py_HUGE_VAL to something that works on your platform.
|
/* Py_HUGE_VAL should always be the same as Py_INFINITY. But historically
|
||||||
|
* this was not reliable and Python did not require IEEE floats and C99
|
||||||
|
* conformity. Prefer Py_INFINITY for new code.
|
||||||
*/
|
*/
|
||||||
#ifndef Py_HUGE_VAL
|
#ifndef Py_HUGE_VAL
|
||||||
# define Py_HUGE_VAL HUGE_VAL
|
# define Py_HUGE_VAL HUGE_VAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Py_NAN: Value that evaluates to a quiet Not-a-Number (NaN).
|
/* Py_NAN: Value that evaluates to a quiet Not-a-Number (NaN). The sign is
|
||||||
|
* undefined and normally not relevant, but e.g. fixed for float("nan").
|
||||||
|
*/
|
||||||
#if !defined(Py_NAN)
|
#if !defined(Py_NAN)
|
||||||
# if _Py__has_builtin(__builtin_nan)
|
|
||||||
// Built-in implementation of the ISO C99 function nan(): quiet NaN.
|
|
||||||
# define Py_NAN (__builtin_nan(""))
|
|
||||||
#else
|
|
||||||
// Use C99 NAN constant: quiet Not-A-Number.
|
|
||||||
// NAN is a float, Py_NAN is a double: cast to double.
|
|
||||||
# define Py_NAN ((double)NAN)
|
# define Py_NAN ((double)NAN)
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* Py_PYMATH_H */
|
#endif /* Py_PYMATH_H */
|
||||||
|
|
|
@ -166,6 +166,11 @@ class CMathTests(unittest.TestCase):
|
||||||
self.assertEqual(cmath.nan.imag, 0.0)
|
self.assertEqual(cmath.nan.imag, 0.0)
|
||||||
self.assertEqual(cmath.nanj.real, 0.0)
|
self.assertEqual(cmath.nanj.real, 0.0)
|
||||||
self.assertTrue(math.isnan(cmath.nanj.imag))
|
self.assertTrue(math.isnan(cmath.nanj.imag))
|
||||||
|
# Also check that the sign of all of these is positive:
|
||||||
|
self.assertEqual(math.copysign(1., cmath.nan.real), 1.)
|
||||||
|
self.assertEqual(math.copysign(1., cmath.nan.imag), 1.)
|
||||||
|
self.assertEqual(math.copysign(1., cmath.nanj.real), 1.)
|
||||||
|
self.assertEqual(math.copysign(1., cmath.nanj.imag), 1.)
|
||||||
|
|
||||||
# Check consistency with reprs.
|
# Check consistency with reprs.
|
||||||
self.assertEqual(repr(cmath.inf), "inf")
|
self.assertEqual(repr(cmath.inf), "inf")
|
||||||
|
|
|
@ -529,6 +529,12 @@ class ComplexTest(unittest.TestCase):
|
||||||
self.assertFloatsAreIdentical(z.real, x)
|
self.assertFloatsAreIdentical(z.real, x)
|
||||||
self.assertFloatsAreIdentical(z.imag, y)
|
self.assertFloatsAreIdentical(z.imag, y)
|
||||||
|
|
||||||
|
def test_constructor_negative_nans_from_string(self):
|
||||||
|
self.assertEqual(copysign(1., complex("-nan").real), -1.)
|
||||||
|
self.assertEqual(copysign(1., complex("-nanj").imag), -1.)
|
||||||
|
self.assertEqual(copysign(1., complex("-nan-nanj").real), -1.)
|
||||||
|
self.assertEqual(copysign(1., complex("-nan-nanj").imag), -1.)
|
||||||
|
|
||||||
def test_underscores(self):
|
def test_underscores(self):
|
||||||
# check underscores
|
# check underscores
|
||||||
for lit in VALID_UNDERSCORE_LITERALS:
|
for lit in VALID_UNDERSCORE_LITERALS:
|
||||||
|
@ -569,6 +575,7 @@ class ComplexTest(unittest.TestCase):
|
||||||
test(complex(NAN, 1), "(nan+1j)")
|
test(complex(NAN, 1), "(nan+1j)")
|
||||||
test(complex(1, NAN), "(1+nanj)")
|
test(complex(1, NAN), "(1+nanj)")
|
||||||
test(complex(NAN, NAN), "(nan+nanj)")
|
test(complex(NAN, NAN), "(nan+nanj)")
|
||||||
|
test(complex(-NAN, -NAN), "(nan+nanj)")
|
||||||
|
|
||||||
test(complex(0, INF), "infj")
|
test(complex(0, INF), "infj")
|
||||||
test(complex(0, -INF), "-infj")
|
test(complex(0, -INF), "-infj")
|
||||||
|
|
|
@ -1040,11 +1040,8 @@ class InfNanTest(unittest.TestCase):
|
||||||
self.assertEqual(copysign(1.0, float('inf')), 1.0)
|
self.assertEqual(copysign(1.0, float('inf')), 1.0)
|
||||||
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):
|
def test_nan_signs(self):
|
||||||
# When using the dtoa.c code, the sign of float('nan') should
|
# The sign of float('nan') should be predictable.
|
||||||
# be predictable.
|
|
||||||
self.assertEqual(copysign(1.0, float('nan')), 1.0)
|
self.assertEqual(copysign(1.0, float('nan')), 1.0)
|
||||||
self.assertEqual(copysign(1.0, float('-nan')), -1.0)
|
self.assertEqual(copysign(1.0, float('-nan')), -1.0)
|
||||||
|
|
||||||
|
|
|
@ -1881,11 +1881,11 @@ class MathTests(unittest.TestCase):
|
||||||
self.assertFalse(math.isinf(0.))
|
self.assertFalse(math.isinf(0.))
|
||||||
self.assertFalse(math.isinf(1.))
|
self.assertFalse(math.isinf(1.))
|
||||||
|
|
||||||
@requires_IEEE_754
|
|
||||||
def test_nan_constant(self):
|
def test_nan_constant(self):
|
||||||
|
# `math.nan` must be a quiet NaN with positive sign bit
|
||||||
self.assertTrue(math.isnan(math.nan))
|
self.assertTrue(math.isnan(math.nan))
|
||||||
|
self.assertEqual(math.copysign(1., math.nan), 1.)
|
||||||
|
|
||||||
@requires_IEEE_754
|
|
||||||
def test_inf_constant(self):
|
def test_inf_constant(self):
|
||||||
self.assertTrue(math.isinf(math.inf))
|
self.assertTrue(math.isinf(math.inf))
|
||||||
self.assertGreater(math.inf, 0.0)
|
self.assertGreater(math.inf, 0.0)
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
Fix ``float("nan")`` to produce a quiet NaN on platforms (like MIPS) where
|
||||||
|
the meaning of the signalling / quiet bit is inverted from its usual
|
||||||
|
meaning. Also introduce a new macro ``Py_INFINITY`` matching C99's
|
||||||
|
``INFINITY``, and refactor internals to rely on C99's ``NAN`` and
|
||||||
|
``INFINITY`` macros instead of hard-coding bit patterns for infinities and
|
||||||
|
NaNs. Thanks Sebastian Berg.
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
|
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
|
||||||
#include "pycore_dtoa.h" // _Py_dg_stdnan()
|
|
||||||
/* we need DBL_MAX, DBL_MIN, DBL_EPSILON, DBL_MANT_DIG and FLT_RADIX from
|
/* we need DBL_MAX, DBL_MIN, DBL_EPSILON, DBL_MANT_DIG and FLT_RADIX from
|
||||||
float.h. We assume that FLT_RADIX is either 2 or 16. */
|
float.h. We assume that FLT_RADIX is either 2 or 16. */
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
@ -88,53 +87,6 @@ else {
|
||||||
#endif
|
#endif
|
||||||
#define CM_SCALE_DOWN (-(CM_SCALE_UP+1)/2)
|
#define CM_SCALE_DOWN (-(CM_SCALE_UP+1)/2)
|
||||||
|
|
||||||
/* Constants cmath.inf, cmath.infj, cmath.nan, cmath.nanj.
|
|
||||||
cmath.nan and cmath.nanj are defined only when either
|
|
||||||
_PY_SHORT_FLOAT_REPR is 1 (which should be
|
|
||||||
the most common situation on machines using an IEEE 754
|
|
||||||
representation), or Py_NAN is defined. */
|
|
||||||
|
|
||||||
static double
|
|
||||||
m_inf(void)
|
|
||||||
{
|
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
return _Py_dg_infinity(0);
|
|
||||||
#else
|
|
||||||
return Py_HUGE_VAL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static Py_complex
|
|
||||||
c_infj(void)
|
|
||||||
{
|
|
||||||
Py_complex r;
|
|
||||||
r.real = 0.0;
|
|
||||||
r.imag = m_inf();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
|
|
||||||
static double
|
|
||||||
m_nan(void)
|
|
||||||
{
|
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
return _Py_dg_stdnan(0);
|
|
||||||
#else
|
|
||||||
return Py_NAN;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static Py_complex
|
|
||||||
c_nanj(void)
|
|
||||||
{
|
|
||||||
Py_complex r;
|
|
||||||
r.real = 0.0;
|
|
||||||
r.imag = m_nan();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* forward declarations */
|
/* forward declarations */
|
||||||
static Py_complex cmath_asinh_impl(PyObject *, Py_complex);
|
static Py_complex cmath_asinh_impl(PyObject *, Py_complex);
|
||||||
|
@ -1274,23 +1226,22 @@ cmath_exec(PyObject *mod)
|
||||||
if (PyModule_AddObject(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) {
|
if (PyModule_AddObject(mod, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (PyModule_AddObject(mod, "inf", PyFloat_FromDouble(m_inf())) < 0) {
|
if (PyModule_AddObject(mod, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_complex infj = {0.0, Py_INFINITY};
|
||||||
if (PyModule_AddObject(mod, "infj",
|
if (PyModule_AddObject(mod, "infj",
|
||||||
PyComplex_FromCComplex(c_infj())) < 0) {
|
PyComplex_FromCComplex(infj)) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
if (PyModule_AddObject(mod, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) {
|
||||||
if (PyModule_AddObject(mod, "nan", PyFloat_FromDouble(m_nan())) < 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (PyModule_AddObject(mod, "nanj",
|
Py_complex nanj = {0.0, fabs(Py_NAN)};
|
||||||
PyComplex_FromCComplex(c_nanj())) < 0) {
|
if (PyModule_AddObject(mod, "nanj", PyComplex_FromCComplex(nanj)) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* initialize special value tables */
|
/* initialize special value tables */
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,6 @@ raised for division by zero and mod by zero.
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "pycore_bitutils.h" // _Py_bit_length()
|
#include "pycore_bitutils.h" // _Py_bit_length()
|
||||||
#include "pycore_call.h" // _PyObject_CallNoArgs()
|
#include "pycore_call.h" // _PyObject_CallNoArgs()
|
||||||
#include "pycore_dtoa.h" // _Py_dg_infinity()
|
|
||||||
#include "pycore_long.h" // _PyLong_GetZero()
|
#include "pycore_long.h" // _PyLong_GetZero()
|
||||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||||
#include "pycore_object.h" // _PyObject_LookupSpecial()
|
#include "pycore_object.h" // _PyObject_LookupSpecial()
|
||||||
|
@ -389,34 +388,6 @@ lanczos_sum(double x)
|
||||||
return num/den;
|
return num/den;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Constant for +infinity, generated in the same way as float('inf'). */
|
|
||||||
|
|
||||||
static double
|
|
||||||
m_inf(void)
|
|
||||||
{
|
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
return _Py_dg_infinity(0);
|
|
||||||
#else
|
|
||||||
return Py_HUGE_VAL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Constant nan value, generated in the same way as float('nan'). */
|
|
||||||
/* We don't currently assume that Py_NAN is defined everywhere. */
|
|
||||||
|
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
|
|
||||||
static double
|
|
||||||
m_nan(void)
|
|
||||||
{
|
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
return _Py_dg_stdnan(0);
|
|
||||||
#else
|
|
||||||
return Py_NAN;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static double
|
static double
|
||||||
m_tgamma(double x)
|
m_tgamma(double x)
|
||||||
|
@ -435,7 +406,7 @@ m_tgamma(double x)
|
||||||
if (x == 0.0) {
|
if (x == 0.0) {
|
||||||
errno = EDOM;
|
errno = EDOM;
|
||||||
/* tgamma(+-0.0) = +-inf, divide-by-zero */
|
/* tgamma(+-0.0) = +-inf, divide-by-zero */
|
||||||
return copysign(Py_HUGE_VAL, x);
|
return copysign(Py_INFINITY, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* integer arguments */
|
/* integer arguments */
|
||||||
|
@ -3938,7 +3909,7 @@ math_ulp_impl(PyObject *module, double x)
|
||||||
if (Py_IS_INFINITY(x)) {
|
if (Py_IS_INFINITY(x)) {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
double inf = m_inf();
|
double inf = Py_INFINITY;
|
||||||
double x2 = nextafter(x, inf);
|
double x2 = nextafter(x, inf);
|
||||||
if (Py_IS_INFINITY(x2)) {
|
if (Py_IS_INFINITY(x2)) {
|
||||||
/* special case: x is the largest positive representable float */
|
/* special case: x is the largest positive representable float */
|
||||||
|
@ -3975,14 +3946,12 @@ math_exec(PyObject *module)
|
||||||
if (PyModule_AddObject(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) {
|
if (PyModule_AddObject(module, "tau", PyFloat_FromDouble(Py_MATH_TAU)) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (PyModule_AddObject(module, "inf", PyFloat_FromDouble(m_inf())) < 0) {
|
if (PyModule_AddObject(module, "inf", PyFloat_FromDouble(Py_INFINITY)) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
if (PyModule_AddObject(module, "nan", PyFloat_FromDouble(fabs(Py_NAN))) < 0) {
|
||||||
if (PyModule_AddObject(module, "nan", PyFloat_FromDouble(m_nan())) < 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2424,25 +2424,14 @@ PyFloat_Unpack2(const char *data, int le)
|
||||||
f |= *p;
|
f |= *p;
|
||||||
|
|
||||||
if (e == 0x1f) {
|
if (e == 0x1f) {
|
||||||
#if _PY_SHORT_FLOAT_REPR == 0
|
|
||||||
if (f == 0) {
|
if (f == 0) {
|
||||||
/* Infinity */
|
/* Infinity */
|
||||||
return sign ? -Py_HUGE_VAL : Py_HUGE_VAL;
|
return sign ? -Py_HUGE_VAL : Py_HUGE_VAL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* NaN */
|
/* NaN */
|
||||||
return sign ? -Py_NAN : Py_NAN;
|
return sign ? -fabs(Py_NAN) : fabs(Py_NAN);
|
||||||
}
|
}
|
||||||
#else // _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
if (f == 0) {
|
|
||||||
/* Infinity */
|
|
||||||
return _Py_dg_infinity(sign);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* NaN */
|
|
||||||
return _Py_dg_stdnan(sign);
|
|
||||||
}
|
|
||||||
#endif // _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
x = (double)f / 1024.0;
|
x = (double)f / 1024.0;
|
||||||
|
|
|
@ -273,11 +273,6 @@ 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. */
|
/* Bits of the representation of positive infinity. */
|
||||||
|
|
||||||
#define POSINF_WORD0 0x7ff00000
|
#define POSINF_WORD0 0x7ff00000
|
||||||
|
@ -1399,35 +1394,6 @@ 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)
|
||||||
|
|
|
@ -23,44 +23,6 @@ case_insensitive_match(const char *s, const char *t)
|
||||||
return the NaN or Infinity as a double and set *endptr to point just beyond
|
return the NaN or Infinity as a double and set *endptr to point just beyond
|
||||||
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. */
|
||||||
|
|
||||||
#if _PY_SHORT_FLOAT_REPR == 1
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -84,7 +46,7 @@ _Py_parse_inf_or_nan(const char *p, char **endptr)
|
||||||
}
|
}
|
||||||
else if (case_insensitive_match(s, "nan")) {
|
else if (case_insensitive_match(s, "nan")) {
|
||||||
s += 3;
|
s += 3;
|
||||||
retval = negate ? -Py_NAN : Py_NAN;
|
retval = negate ? -fabs(Py_NAN) : fabs(Py_NAN);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
s = p;
|
s = p;
|
||||||
|
@ -94,7 +56,6 @@ _Py_parse_inf_or_nan(const char *p, char **endptr)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _PyOS_ascii_strtod:
|
* _PyOS_ascii_strtod:
|
||||||
|
|
Loading…
Reference in New Issue