Commit cec3f138 authored by Mark Dickinson's avatar Mark Dickinson

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.
parent b2f70902
......@@ -498,6 +498,18 @@ class MathTests(unittest.TestCase):
self.assertEqual(math.pow(-1.1, 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
# really belong here: the implementation of ** for floats is
# independent of the implemention of math.pow
......
......@@ -522,7 +522,7 @@ math_pow(PyObject *self, PyObject *args)
{
PyObject *ox, *oy;
double r, x, y;
int y_is_odd;
int odd_y;
if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy))
return NULL;
......@@ -531,53 +531,61 @@ math_pow(PyObject *self, PyObject *args)
if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
return NULL;
/* deal directly with various special cases, to cope with problems on
various platforms whose semantics don't exactly match C99 */
/* 1**x, x**0, and (-1)**(+-infinity) return 1., even if x is NaN or
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))
return PyFloat_FromDouble(x);
if (Py_IS_NAN(y))
return PyFloat_FromDouble(y);
/* inf ** (nonzero, non-NaN) is one of +-0, +-infinity */
if (Py_IS_INFINITY(x) && !Py_IS_NAN(y)) {
y_is_odd = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0;
if (y > 0.)
r = y_is_odd ? x : fabs(x);
else
r = y_is_odd ? copysign(0., x) : 0.;
return PyFloat_FromDouble(r);
}
errno = 0;
PyFPE_START_PROTECT("in math_pow", return 0);
r = pow(x, y);
PyFPE_END_PROTECT(r);
if (Py_IS_NAN(r)) {
errno = EDOM;
/* deal directly with IEEE specials, to cope with problems on various
platforms whose semantics don't exactly match C99 */
if (!Py_IS_FINITE(x) || !Py_IS_FINITE(y)) {
errno = 0;
if (Py_IS_NAN(x))
r = y == 0. ? 1. : x; /* NaN**0 = 1 */
else if (Py_IS_NAN(y))
r = x == 1. ? 1. : y; /* 1**NaN = 1 */
else if (Py_IS_INFINITY(x)) {
odd_y = Py_IS_FINITE(y) && fmod(fabs(y), 2.0) == 1.0;
if (y > 0.)
r = odd_y ? x : fabs(x);
else if (y == 0.)
r = 1.;
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.;
}
}
/* an infinite result arises either from:
(A) (+/-0.)**negative,
(B) overflow of x**y with both x and y finite (and x nonzero)
(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)) {
if (x == 0.)
errno = EDOM;
else if (Py_IS_FINITE(x) && Py_IS_FINITE(y))
errno = ERANGE;
else
errno = 0;
else {
/* let libm handle finite**finite */
errno = 0;
PyFPE_START_PROTECT("in math_pow", return 0);
r = pow(x, y);
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)) {
errno = EDOM;
}
/*
an infinite result here arises either from:
(A) (+/-0.)**negative (-> divide-by-zero)
(B) overflow of x**y with x and y finite
*/
else if (Py_IS_INFINITY(r)) {
if (x == 0.)
errno = EDOM;
else
errno = ERANGE;
}
}
}
if (errno && is_error(r))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment