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.
This commit is contained in:
parent
0ed39577dd
commit
e87568dd9a
@ -101,6 +101,23 @@ class PowTest(unittest.TestCase):
|
|||||||
return None
|
return None
|
||||||
None ** TestRpow() # Won't fail when __rpow__ invoked. SF bug #643260.
|
None ** TestRpow() # Won't fail when __rpow__ invoked. SF bug #643260.
|
||||||
|
|
||||||
|
def test_bug705231(self):
|
||||||
|
# -1.0 raised to an integer should never blow up. It did if the
|
||||||
|
# platform pow() was buggy, and Python didn't worm around it.
|
||||||
|
eq = self.assertEquals
|
||||||
|
a = -1.0
|
||||||
|
eq(pow(a, 1.23e167), 1.0)
|
||||||
|
eq(pow(a, -1.23e167), 1.0)
|
||||||
|
for b in range(-10, 11):
|
||||||
|
eq(pow(a, float(b)), b & 1 and -1.0 or 1.0)
|
||||||
|
for n in range(0, 100):
|
||||||
|
fiveto = float(5 ** n)
|
||||||
|
# For small n, fiveto will be odd. Eventually we run out of
|
||||||
|
# mantissa bits, though, and thereafer fiveto will be even.
|
||||||
|
expected = fiveto % 2.0 and -1.0 or 1.0
|
||||||
|
eq(pow(a, fiveto), expected)
|
||||||
|
eq(pow(a, -fiveto), expected)
|
||||||
|
eq(expected, 1.0) # else we didn't push fiveto to evenness
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
test.test_support.run_unittest(PowTest)
|
test.test_support.run_unittest(PowTest)
|
||||||
|
@ -12,6 +12,12 @@ What's New in Python 2.3 beta 2?
|
|||||||
Core and builtins
|
Core and builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- SF bug 705231: builtin pow() no longer lets the platform C pow()
|
||||||
|
raise -1.0 to integer powers, because (at least) glibc gets it wrong
|
||||||
|
in some cases. The result should be -1.0 if the power is odd and 1.0
|
||||||
|
if the power is even, and any float with a sufficiently large exponent
|
||||||
|
is (mathematically) an exact even integer.
|
||||||
|
|
||||||
- The encoding attribute has been added for file objects, and set to
|
- The encoding attribute has been added for file objects, and set to
|
||||||
the terminal encoding on Unix and Windows.
|
the terminal encoding on Unix and Windows.
|
||||||
|
|
||||||
|
@ -572,19 +572,51 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
|
|||||||
}
|
}
|
||||||
return PyFloat_FromDouble(0.0);
|
return PyFloat_FromDouble(0.0);
|
||||||
}
|
}
|
||||||
if (iv < 0.0 && iw != floor(iw)) {
|
if (iv < 0.0) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
/* Whether this is an error is a mess, and bumps into libm
|
||||||
"negative number cannot be raised to a fractional power");
|
* 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;
|
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;
|
errno = 0;
|
||||||
PyFPE_START_PROTECT("pow", return NULL)
|
PyFPE_START_PROTECT("pow", return NULL)
|
||||||
ix = pow(iv, iw);
|
ix = pow(iv, iw);
|
||||||
PyFPE_END_PROTECT(ix)
|
PyFPE_END_PROTECT(ix)
|
||||||
Py_ADJUST_ERANGE1(ix);
|
Py_ADJUST_ERANGE1(ix);
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
assert(errno == ERANGE);
|
/* We don't expect any errno value other than ERANGE, but
|
||||||
PyErr_SetFromErrno(PyExc_OverflowError);
|
* the range of libm bugs appears unbounded.
|
||||||
|
*/
|
||||||
|
PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError :
|
||||||
|
PyExc_ValueError);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return PyFloat_FromDouble(ix);
|
return PyFloat_FromDouble(ix);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user