summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-05-24 20:18:24 (GMT)
committerTim Peters <tim.peters@gmail.com>2003-05-24 20:18:24 (GMT)
commite87568dd9a8a1ccdcc05398c19ab45243b1979b5 (patch)
tree5516eedc9948940cbd255179e81017ae54bf6433 /Objects
parent0ed39577ddcc7dadb642b316eb90e91b60bacdcc (diff)
downloadcpython-e87568dd9a8a1ccdcc05398c19ab45243b1979b5.zip
cpython-e87568dd9a8a1ccdcc05398c19ab45243b1979b5.tar.gz
cpython-e87568dd9a8a1ccdcc05398c19ab45243b1979b5.tar.bz2
SF bug 705231: Assertion failed, python aborts.
float_pow(): Don't let the platform pow() raise -1.0 to an integer power anymore; at least glibc gets it wrong in some cases. Note that math.pow() will continue to deliver wrong (but platform-native) results in such cases.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/floatobject.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index f7601ba..f36479f 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -572,10 +572,39 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
}
return PyFloat_FromDouble(0.0);
}
- if (iv < 0.0 && iw != floor(iw)) {
- PyErr_SetString(PyExc_ValueError,
- "negative number cannot be raised to a fractional power");
- return NULL;
+ if (iv < 0.0) {
+ /* Whether this is an error is a mess, and bumps into libm
+ * bugs so we have to figure it out ourselves.
+ */
+ if (iw != floor(iw)) {
+ PyErr_SetString(PyExc_ValueError, "negative number "
+ "cannot be raised to a fractional power");
+ return NULL;
+ }
+ /* iw is an exact integer, albeit perhaps a very large one.
+ * -1 raised to an exact integer should never be exceptional.
+ * Alas, some libms (chiefly glibc as of early 2003) return
+ * NaN and set EDOM on pow(-1, large_int) if the int doesn't
+ * happen to be representable in a *C* integer. That's a
+ * bug; we let that slide in math.pow() (which currently
+ * reflects all platform accidents), but not for Python's **.
+ */
+ if (iv == -1.0 && !Py_IS_INFINITY(iw) && iw == iw) {
+ /* XXX the "iw == iw" was to weed out NaNs. This
+ * XXX doesn't actually work on all platforms.
+ */
+ /* Return 1 if iw is even, -1 if iw is odd; there's
+ * no guarantee that any C integral type is big
+ * enough to hold iw, so we have to check this
+ * indirectly.
+ */
+ ix = floor(iw * 0.5) * 2.0;
+ return PyFloat_FromDouble(ix == iw ? 1.0 : -1.0);
+ }
+ /* Else iv != -1.0, and overflow or underflow are possible.
+ * Unless we're to write pow() ourselves, we have to trust
+ * the platform to do this correctly.
+ */
}
errno = 0;
PyFPE_START_PROTECT("pow", return NULL)
@@ -583,8 +612,11 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
PyFPE_END_PROTECT(ix)
Py_ADJUST_ERANGE1(ix);
if (errno != 0) {
- assert(errno == ERANGE);
- PyErr_SetFromErrno(PyExc_OverflowError);
+ /* We don't expect any errno value other than ERANGE, but
+ * the range of libm bugs appears unbounded.
+ */
+ PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError :
+ PyExc_ValueError);
return NULL;
}
return PyFloat_FromDouble(ix);