]> granicus.if.org Git - python/commitdiff
SF bug 525705: [2.2] underflow raise OverflowException.
authorTim Peters <tim.peters@gmail.com>
Sat, 9 Mar 2002 04:58:24 +0000 (04:58 +0000)
committerTim Peters <tim.peters@gmail.com>
Sat, 9 Mar 2002 04:58:24 +0000 (04:58 +0000)
Another year in the quest to out-guess random C behavior.

Added macros Py_ADJUST_ERANGE1(X) and Py_ADJUST_ERANGE2(X, Y).  The latter
is useful for functions with complex results.  Two corrections to errno-
after-libm-call are attempted:

1. If the platform set errno to ERANGE due to underflow, clear errno.
   Some unknown subset of libm versions and link options do this.  It's
   allowed by C89, but I never figured anyone would do it.

2. If the platform did not set errno but overflow occurred, force
   errno to ERANGE.  C89 required setting errno to ERANGE, but C99
   doesn't.  Some unknown subset of libm versions and link options do
   it the C99 way now.

Bugfix candidate, but hold off until some Linux people actually try it,
with and without -lieee.  I'll send a help plea to Python-Dev.

Include/pyport.h
Modules/cmathmodule.c
Objects/floatobject.c

index a831b264f9f40fbc32f09ba14b9bcb1a751fa8b3..b311bd89b445e28076a45d1a437b8b6f97b4e2da 100644 (file)
@@ -287,6 +287,41 @@ extern "C" {
                        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.)
index adf76b8a331dd5e3b228c283d91dd3ad3e1d97e3..6e79680843673858e16cadab98a499b79c4738d2 100644 (file)
@@ -337,8 +337,7 @@ math_1(PyObject *args, Py_complex (*func)(Py_complex))
        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
index ec8f71940b286f13169eac7b0a3bb93f2b919d8b..83987baa6b20cda13e2559def0843d0ce53abfc2 100644 (file)
@@ -577,9 +577,9 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
        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;
        }