[Python-checkins] r60402 - python/branches/trunk-math/Modules/mathmodule.c
mark.dickinson
python-checkins at python.org
Mon Jan 28 23:31:57 CET 2008
Author: mark.dickinson
Date: Mon Jan 28 23:31:57 2008
New Revision: 60402
Modified:
python/branches/trunk-math/Modules/mathmodule.c
Log:
Rework math_1 so that the NaN-checking occurs after the function call, not before.
math_1 now looks more like it did originally, it reads more cleanly, and it does
the right thing for fabs(NaN) on OS X (where the default NaN has its sign bit set).
Also added some additional comments explaining the changes to math_1.
Modified: python/branches/trunk-math/Modules/mathmodule.c
==============================================================================
--- python/branches/trunk-math/Modules/mathmodule.c (original)
+++ python/branches/trunk-math/Modules/mathmodule.c Mon Jan 28 23:31:57 2008
@@ -95,41 +95,49 @@
return result;
}
+/* In math_1, the following rules are used to try to ensure that
+ functions raise the correct exceptions both on ANSI C platforms and
+ on C99 platforms:
+
+ (1) Whenever a non-NaN argument gives a NaN result, set errno = EDOM
+ to force Python to raise a ValueError.
+
+ (2) Whenever a finite argument gives an infinite result, set errno
+ to either EDOM or ERANGE to force Python to raise ValueError or
+ OverflowError respectively. The "can_overflow" argument should be
+ set to 1 for functions which might overflow but never raise
+ "divide-by-zero", and 0 for functions that never overflow.
+ Fortunately, none of the single-argument functions currently
+ implemented can raise both "divide-by-zero" *and* "overflow".
+
+ (3) If neither of the above occurred but errno was set by the libm
+ function (this can happen in cases where Py_HUGE_VAL is not an
+ infinity) then raise OverflowError if errno==ERANGE and the result
+ was nonzero, do nothing if errno==ERANGE and the result was zero
+ (this can happen on underflow under ANSI C), and raise ValueError
+ if errno==EDOM.
+
+*/
+
static PyObject *
math_1(PyObject *arg, double (*func) (double), int can_overflow)
{
- int x_is_infinity;
- double x = PyFloat_AsDouble(arg);
+ double x, r;
+ x = PyFloat_AsDouble(arg);
if (x == -1.0 && PyErr_Occurred())
return NULL;
- /* a NaN input should be returned unscathed */
- if (Py_IS_NAN(x))
- return PyFloat_FromDouble(x);
- x_is_infinity = Py_IS_INFINITY(x);
errno = 0;
PyFPE_START_PROTECT("in math_1", return 0);
- x = (*func)(x);
- PyFPE_END_PROTECT(x);
-
- /* if the result was a NaN then we should be signalling a ValueError;
- this should only happen in the cases where C99 recommends raising
- invalid */
- if (Py_IS_NAN(x))
+ r = (*func)(x);
+ PyFPE_END_PROTECT(r);
+ if (!Py_IS_NAN(x) && Py_IS_NAN(r))
errno = EDOM;
-
- /* if the input was finite and the result is an infinity, then either
- overflow occurred and we should be setting errno to ERANGE so that
- Python raises an OverflowError, or we were evaluating at a
- singularity, and we should setting errno to EDOM so that Python
- raises ValueError. Currently, none of the functions using math_1
- have singularities *and* the possibility of overflow :-) */
- if (!x_is_infinity && Py_IS_INFINITY(x))
+ if (Py_IS_FINITE(x) && Py_IS_INFINITY(r))
errno = can_overflow ? ERANGE : EDOM;
-
- if (errno && is_error(x))
+ if (errno && is_error(r))
return NULL;
else
- return PyFloat_FromDouble(x);
+ return PyFloat_FromDouble(r);
}
static PyObject *
More information about the Python-checkins
mailing list