diff options
author | Tim Peters <tim.peters@gmail.com> | 2003-05-24 20:18:24 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2003-05-24 20:18:24 (GMT) |
commit | e87568dd9a8a1ccdcc05398c19ab45243b1979b5 (patch) | |
tree | 5516eedc9948940cbd255179e81017ae54bf6433 /Objects | |
parent | 0ed39577ddcc7dadb642b316eb90e91b60bacdcc (diff) | |
download | cpython-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.c | 44 |
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); |