errno = ERANGE; \
} while(0)
+/* Py_ADJUST_ERANGE1(x)
+ * Py_ADJUST_ERANGE2(x, y)
+ * Set errno to 0 before calling a libm function, and invoke one of these
+ * macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful
+ * for functions returning complex results). This makes two kinds of
+ * adjustments to errno: (A) If it looks like the platform libm set
+ * errno=ERANGE due to underflow, clear errno. (B) If it looks like the
+ * platform libm overflowed but didn't set errno, force errno to ERANGE. In
+ * effect, we're trying to force a useful implementation of C89 errno
+ * behavior.
+ * Caution:
+ * This isn't reliable. See Py_OVERFLOWED comments.
+ * X and Y may be evaluated more than once.
+ */
+#define Py_ADJUST_ERANGE1(X) \
+ do { \
+ if (errno == 0) { \
+ if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \
+ errno = ERANGE; \
+ } \
+ else if (errno == ERANGE && (X) == 0.0) \
+ errno = 0; \
+ } while(0)
+
+#define Py_ADJUST_ERANGE2(X, Y) \
+ do { \
+ if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \
+ (Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \
+ if (errno == 0) \
+ errno = ERANGE; \
+ } \
+ else if (errno == ERANGE) \
+ errno = 0; \
+ } while(0)
+
/**************************************************************************
Prototypes that are missing from the standard include files on some systems
(and possibly only some versions of such systems.)
PyFPE_START_PROTECT("complex function", return 0)
x = (*func)(x);
PyFPE_END_PROTECT(x)
- Py_SET_ERANGE_IF_OVERFLOW(x.real);
- Py_SET_ERANGE_IF_OVERFLOW(x.imag);
+ Py_ADJUST_ERANGE2(x.real, x.imag);
if (errno != 0)
return math_error();
else
PyFPE_START_PROTECT("pow", return NULL)
ix = pow(iv, iw);
PyFPE_END_PROTECT(ix)
- Py_SET_ERANGE_IF_OVERFLOW(ix);
+ Py_ADJUST_ERANGE1(ix);
if (errno != 0) {
- /* XXX could it be another type of error? */
+ assert(errno == ERANGE);
PyErr_SetFromErrno(PyExc_OverflowError);
return NULL;
}