summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/pyport.h33
-rw-r--r--Lib/test/test_math.py2
-rw-r--r--Misc/NEWS7
-rw-r--r--Modules/cmathmodule.c17
-rw-r--r--Modules/mathmodule.c42
-rw-r--r--Objects/floatobject.c17
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:
diff --git a/Misc/NEWS b/Misc/NEWS
index 02d4968..50ec64f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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);