*/
#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
* 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
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:
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.
#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
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
#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
*/
static double atan2_sco(double x, double y)
{
- if (x == 0.0)
+ if (x == 0.0)
return (double)0.0;
return atan2(x, y);
}
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,
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
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
return NULL;
errno = 0;
x = frexp(x, &i);
- CHECK(x);
+ Py_SET_ERANGE_IF_OVERFLOW(x);
if (errno && is_error(x))
return NULL;
else
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
#else
x = modf(x, &y);
#endif
- CHECK(x);
+ Py_SET_ERANGE_IF_OVERFLOW(x);
if (errno && is_error(x))
return NULL;
else
#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);
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);