diff options
-rw-r--r-- | Include/pyport.h | 33 | ||||
-rw-r--r-- | Lib/test/test_math.py | 2 | ||||
-rw-r--r-- | Misc/NEWS | 7 | ||||
-rw-r--r-- | Modules/cmathmodule.c | 17 | ||||
-rw-r--r-- | Modules/mathmodule.c | 42 | ||||
-rw-r--r-- | Objects/floatobject.c | 17 |
6 files changed, 54 insertions, 64 deletions
diff --git a/Include/pyport.h b/Include/pyport.h index 0363953..15a480a 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -230,6 +230,18 @@ extern "C" { */ #define Py_IS_INFINITY(X) ((X) && (X)*0.5 == (X)) +/* According to + * http://www.cray.com/swpubs/manuals/SN-2194_2.0/html-SN-2194_2.0/x3138.htm + * on some Cray systems HUGE_VAL is incorrectly (according to the C std) + * defined to be the largest positive finite rather than infinity. We need + * the std-conforming infinity meaning (provided the platform has one!). + */ +#ifdef INFINITY +#define Py_HUGE_VAL INFINITY +#else +#define Py_HUGE_VAL HUGE_VAL +#endif + /* Py_OVERFLOWED(X) * Return 1 iff a libm function overflowed. Set errno to 0 before calling * a libm function, and invoke this macro after, passing the function @@ -246,9 +258,24 @@ extern "C" { * in non-overflow cases. * X is evaluated more than once. */ -#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \ - (X) == HUGE_VAL || \ - (X) == -HUGE_VAL)) +#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \ + (X) == Py_HUGE_VAL || \ + (X) == -Py_HUGE_VAL)) + +/* Py_SET_ERANGE_ON_OVERFLOW(x) + * If a libm function did not set errno, but it looks like the result + * overflowed, set errno to ERANGE. Set errno to 0 before calling a libm + * function, and invoke this macro after, passing the function result. + * Caution: + * This isn't reliable. See Py_OVERFLOWED comments. + * X is evaluated more than once. + */ +#define Py_SET_ERANGE_IF_OVERFLOW(X) \ + do { \ + if (errno == 0 && ((X) == Py_HUGE_VAL || \ + (X) == -Py_HUGE_VAL)) \ + errno = ERANGE; \ + } while(0) /************************************************************************** Prototypes that are missing from the standard include files on some systems diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 8419a1f..743d46b 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -181,7 +181,7 @@ def test_exceptions(): raise TestFailed("overflowing exp() didn't trigger OverflowError") # If this fails, it could be a puzzle. One odd possibility is that - # mathmodule.c's CHECK() macro is getting confused while comparing + # mathmodule.c's macros are getting confused while comparing # Inf (HUGE_VAL) to a NaN, and artificially setting errno to ERANGE # as a result (and so raising OverflowError instead). try: @@ -81,6 +81,13 @@ Core Library +- The new C standard no longer requires that math libraries set errno to + ERANGE on overflow. For platform libraries that exploit this new + freedom, Python's overflow-checking was wholly broken. A new overflow- + checking scheme attempts to repair that, but may not be reliable on all + platforms (C doesn't seem to provide anything both useful and portable + in this area anymore). + - Asynchronous timeout actions are available through the new class threading.Timer. diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 2cef27c..34b0ce8 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -4,19 +4,6 @@ #include "Python.h" -#ifdef i860 -/* Cray APP has bogus definition of HUGE_VAL in <math.h> */ -#undef HUGE_VAL -#endif - -#ifdef HUGE_VAL -#define CHECK(x) if (errno != 0) ; \ - else if (-HUGE_VAL <= (x) && (x) <= HUGE_VAL) ; \ - else errno = ERANGE -#else -#define CHECK(x) /* Don't know how to check */ -#endif - #ifndef M_PI #define M_PI (3.141592653589793239) #endif @@ -366,8 +353,8 @@ math_1(PyObject *args, Py_complex (*func)(Py_complex)) PyFPE_START_PROTECT("complex function", return 0) x = (*func)(x); PyFPE_END_PROTECT(x) - CHECK(x.real); - CHECK(x.imag); + Py_SET_ERANGE_IF_OVERFLOW(x.real); + Py_SET_ERANGE_IF_OVERFLOW(x.imag); if (errno != 0) return math_error(); else diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 7f4839a..379fecb 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -12,25 +12,6 @@ extern double modf (double, double *); #endif /* __STDC__ */ #endif /* _MSC_VER */ - -#ifdef i860 -/* Cray APP has bogus definition of HUGE_VAL in <math.h> */ -#undef HUGE_VAL -#endif - -/* RED_FLAG 12-Oct-2000 Tim - * What CHECK does if errno == 0 and x is a NaN is a platform-dependent crap - * shoot. Most (but not all!) platforms will end up setting errno to ERANGE - * then, but EDOM is probably better. - */ -#ifdef HUGE_VAL -#define CHECK(x) if (errno != 0) ; \ - else if (-HUGE_VAL <= (x) && (x) <= HUGE_VAL) ; \ - else errno = ERANGE -#else -#define CHECK(x) /* Don't know how to check */ -#endif - #ifdef SCO_ATAN2_BUG /* * UnixWare 7+ is known to have a bug in atan2 that will return PI instead @@ -38,7 +19,7 @@ extern double modf (double, double *); */ static double atan2_sco(double x, double y) { - if (x == 0.0) + if (x == 0.0) return (double)0.0; return atan2(x, y); } @@ -58,14 +39,17 @@ is_error(double x) assert(errno); /* non-zero errno is a precondition for calling */ if (errno == EDOM) PyErr_SetString(PyExc_ValueError, "math domain error"); + else if (errno == ERANGE) { /* ANSI C generally requires libm functions to set ERANGE * on overflow, but also generally *allows* them to set * ERANGE on underflow too. There's no consistency about - * the latter across platforms. Here we suppress the - * underflow errors (libm functions should return a zero - * on underflow, and +- HUGE_VAL on overflow, so testing - * the result for zero suffices to distinguish the cases). + * the latter across platforms. + * Alas, C99 never requires that errno be set. + * Here we suppress the underflow errors (libm functions + * should return a zero on underflow, and +- HUGE_VAL on + * overflow, so testing the result for zero suffices to + * distinguish the cases). */ if (x) PyErr_SetString(PyExc_OverflowError, @@ -89,7 +73,7 @@ math_1(PyObject *args, double (*func) (double), char *argsfmt) PyFPE_START_PROTECT("in math_1", return 0) x = (*func)(x); PyFPE_END_PROTECT(x) - CHECK(x); + Py_SET_ERANGE_IF_OVERFLOW(x); if (errno && is_error(x)) return NULL; else @@ -106,7 +90,7 @@ math_2(PyObject *args, double (*func) (double, double), char *argsfmt) PyFPE_START_PROTECT("in math_2", return 0) x = (*func)(x, y); PyFPE_END_PROTECT(x) - CHECK(x); + Py_SET_ERANGE_IF_OVERFLOW(x); if (errno && is_error(x)) return NULL; else @@ -180,7 +164,7 @@ math_frexp(PyObject *self, PyObject *args) return NULL; errno = 0; x = frexp(x, &i); - CHECK(x); + Py_SET_ERANGE_IF_OVERFLOW(x); if (errno && is_error(x)) return NULL; else @@ -205,7 +189,7 @@ math_ldexp(PyObject *self, PyObject *args) PyFPE_START_PROTECT("ldexp", return 0) x = ldexp(x, exp); PyFPE_END_PROTECT(x) - CHECK(x); + Py_SET_ERANGE_IF_OVERFLOW(x); if (errno && is_error(x)) return NULL; else @@ -231,7 +215,7 @@ math_modf(PyObject *self, PyObject *args) #else x = modf(x, &y); #endif - CHECK(x); + Py_SET_ERANGE_IF_OVERFLOW(x); if (errno && is_error(x)) return NULL; else diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 258c4dd..adeaa9e 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -8,21 +8,6 @@ #include <ctype.h> -#ifdef i860 -/* Cray APP has bogus definition of HUGE_VAL in <math.h> */ -#undef HUGE_VAL -#endif - -#if defined(HUGE_VAL) && !defined(CHECK) -#define CHECK(x) if (errno != 0) ; \ - else if (-HUGE_VAL <= (x) && (x) <= HUGE_VAL) ; \ - else errno = ERANGE -#endif - -#ifndef CHECK -#define CHECK(x) /* Don't know how to check */ -#endif - #if !defined(__STDC__) && !defined(macintosh) extern double fmod(double, double); extern double pow(double, double); @@ -535,7 +520,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) PyFPE_START_PROTECT("pow", return NULL) ix = pow(iv, iw); PyFPE_END_PROTECT(ix) - CHECK(ix); + Py_SET_ERANGE_IF_OVERFLOW(ix); if (errno != 0) { /* XXX could it be another type of error? */ PyErr_SetFromErrno(PyExc_OverflowError); |