Yet more explicit special case handling to make
math.pow behave on alpha Tru64. All IEEE 754 special values are now handled directly; only the finite**finite case is handled by libm.
This commit is contained in:
parent
b2f7090239
commit
cec3f138d8
|
@ -498,6 +498,18 @@ class MathTests(unittest.TestCase):
|
||||||
self.assertEqual(math.pow(-1.1, INF), INF)
|
self.assertEqual(math.pow(-1.1, INF), INF)
|
||||||
self.assertEqual(math.pow(-1.9, INF), INF)
|
self.assertEqual(math.pow(-1.9, INF), INF)
|
||||||
|
|
||||||
|
# pow(x, y) should work for x negative, y an integer
|
||||||
|
self.ftest('(-2.)**3.', math.pow(-2.0, 3.0), -8.0)
|
||||||
|
self.ftest('(-2.)**2.', math.pow(-2.0, 2.0), 4.0)
|
||||||
|
self.ftest('(-2.)**1.', math.pow(-2.0, 1.0), -2.0)
|
||||||
|
self.ftest('(-2.)**0.', math.pow(-2.0, 0.0), 1.0)
|
||||||
|
self.ftest('(-2.)**-0.', math.pow(-2.0, -0.0), 1.0)
|
||||||
|
self.ftest('(-2.)**-1.', math.pow(-2.0, -1.0), -0.5)
|
||||||
|
self.ftest('(-2.)**-2.', math.pow(-2.0, -2.0), 0.25)
|
||||||
|
self.ftest('(-2.)**-3.', math.pow(-2.0, -3.0), -0.125)
|
||||||
|
self.assertRaises(ValueError, math.pow, -2.0, -0.5)
|
||||||
|
self.assertRaises(ValueError, math.pow, -2.0, 0.5)
|
||||||
|
|
||||||
# the following tests have been commented out since they don't
|
# the following tests have been commented out since they don't
|
||||||
# really belong here: the implementation of ** for floats is
|
# really belong here: the implementation of ** for floats is
|
||||||
# independent of the implemention of math.pow
|
# independent of the implemention of math.pow
|
||||||
|
|
|
@ -522,7 +522,7 @@ math_pow(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *ox, *oy;
|
PyObject *ox, *oy;
|
||||||
double r, x, y;
|
double r, x, y;
|
||||||
int y_is_odd;
|
int odd_y;
|
||||||
|
|
||||||
if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
|
if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -531,53 +531,61 @@ math_pow(PyObject *self, PyObject *args)
|
||||||
if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
|
if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* deal directly with various special cases, to cope with problems on
|
/* deal directly with IEEE specials, to cope with problems on various
|
||||||
various platforms whose semantics don't exactly match C99 */
|
platforms whose semantics don't exactly match C99 */
|
||||||
|
if (!Py_IS_FINITE(x) || !Py_IS_FINITE(y)) {
|
||||||
/* 1**x, x**0, and (-1)**(+-infinity) return 1., even if x is NaN or
|
errno = 0;
|
||||||
an infinity. */
|
|
||||||
if (x == 1. || y == 0. || (x == -1. && Py_IS_INFINITY(y)))
|
|
||||||
return PyFloat_FromDouble(1.);
|
|
||||||
/* otherwise, return a NaN if either input was a NaN */
|
|
||||||
if (Py_IS_NAN(x))
|
if (Py_IS_NAN(x))
|
||||||
return PyFloat_FromDouble(x);
|
r = y == 0. ? 1. : x; /* NaN**0 = 1 */
|
||||||
if (Py_IS_NAN(y))
|
else if (Py_IS_NAN(y))
|
||||||
return PyFloat_FromDouble(y);
|
r = x == 1. ? 1. : y; /* 1**NaN = 1 */
|
||||||
/* inf ** (nonzero, non-NaN) is one of +-0, +-infinity */
|
else if (Py_IS_INFINITY(x)) {
|
||||||
if (Py_IS_INFINITY(x) && !Py_IS_NAN(y)) {
|
odd_y = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0;
|
||||||
y_is_odd = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0;
|
|
||||||
if (y > 0.)
|
if (y > 0.)
|
||||||
r = y_is_odd ? x : fabs(x);
|
r = odd_y ? x : fabs(x);
|
||||||
else
|
else if (y == 0.)
|
||||||
r = y_is_odd ? copysign(0., x) : 0.;
|
r = 1.;
|
||||||
return PyFloat_FromDouble(r);
|
else /* y < 0. */
|
||||||
|
r = odd_y ? copysign(0., x) : 0.;
|
||||||
}
|
}
|
||||||
|
else if (Py_IS_INFINITY(y)) {
|
||||||
|
if (fabs(x) == 1.0)
|
||||||
|
r = 1.;
|
||||||
|
else if (y > 0. && fabs(x) > 1.0)
|
||||||
|
r = y;
|
||||||
|
else if (y < 0. && fabs(x) < 1.0) {
|
||||||
|
r = -y; /* result is +inf */
|
||||||
|
if (x == 0.) /* 0**-inf: divide-by-zero */
|
||||||
|
errno = EDOM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = 0.;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* let libm handle finite**finite */
|
||||||
errno = 0;
|
errno = 0;
|
||||||
PyFPE_START_PROTECT("in math_pow", return 0);
|
PyFPE_START_PROTECT("in math_pow", return 0);
|
||||||
r = pow(x, y);
|
r = pow(x, y);
|
||||||
PyFPE_END_PROTECT(r);
|
PyFPE_END_PROTECT(r);
|
||||||
|
/* a NaN result should arise only from (-ve)**(finite
|
||||||
|
non-integer); in this case we want to raise ValueError. */
|
||||||
|
if (!Py_IS_FINITE(r)) {
|
||||||
if (Py_IS_NAN(r)) {
|
if (Py_IS_NAN(r)) {
|
||||||
errno = EDOM;
|
errno = EDOM;
|
||||||
}
|
}
|
||||||
/* an infinite result arises either from:
|
/*
|
||||||
|
an infinite result here arises either from:
|
||||||
(A) (+/-0.)**negative,
|
(A) (+/-0.)**negative (-> divide-by-zero)
|
||||||
(B) overflow of x**y with both x and y finite (and x nonzero)
|
(B) overflow of x**y with x and y finite
|
||||||
(C) (+/-inf)**positive, or
|
|
||||||
(D) x**inf with |x| > 1, or x**-inf with |x| < 1.
|
|
||||||
|
|
||||||
In case (A) we want ValueError to be raised. In case (B)
|
|
||||||
OverflowError should be raised. In cases (C) and (D) the infinite
|
|
||||||
result should be returned.
|
|
||||||
*/
|
*/
|
||||||
else if (Py_IS_INFINITY(r)) {
|
else if (Py_IS_INFINITY(r)) {
|
||||||
if (x == 0.)
|
if (x == 0.)
|
||||||
errno = EDOM;
|
errno = EDOM;
|
||||||
else if (Py_IS_FINITE(x) && Py_IS_FINITE(y))
|
|
||||||
errno = ERANGE;
|
|
||||||
else
|
else
|
||||||
errno = 0;
|
errno = ERANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errno && is_error(r))
|
if (errno && is_error(r))
|
||||||
|
|
Loading…
Reference in New Issue