Author: tismer
Date: Fri Dec 12 23:47:30 2008
New Revision: 60481
Modified:
psyco/branch/devel/c/Modules/pmath.c
Log:
cleaning up my priority list.
Modified: psyco/branch/devel/c/Modules/pmath.c
==============================================================================
--- psyco/branch/devel/c/Modules/pmath.c (original)
+++ psyco/branch/devel/c/Modules/pmath.c Fri Dec 12 23:47:30 2008
@@ -2,6 +2,7 @@
* Psyco version of python math module, mathmodule.c
*
* TODO:
+ * - raise python exceptions on math errors (domain error etc)
* - implement:
* - frexp()
* - ldexp()
@@ -10,7 +11,6 @@
* - modf()
* - degrees()
* - radians()
- * ... etc. See the method table of Python 2.6's mathmodule.c
*/
#include "../initialize.h"
@@ -31,135 +31,22 @@
#include <math.h>
-/* taken from Python 2.6's mathmodule.c */
-
-/* Call is_error when errno != 0, and where x is the result libm
- * returned. is_error will usually set up an exception and return
- * true (1), but may return false (0) without setting up an exception.
- */
-static int
-is_error(double x)
-{
- int result = 1; /* presumption of guilt */
- assert(errno); /* non-zero errno is a precondition for calling */
- if (errno == EDOM)
- PyErr_SetString(PyExc_ValueError, "math domain error");
-
- else if (errno == ERANGE) {
- /* ANSI C generally requires libm functions to set ERANGE
- * on overflow, but also generally *allows* them to set
- * ERANGE on underflow too. There's no consistency about
- * the latter across platforms.
- * Alas, C99 never requires that errno be set.
- * Here we suppress the underflow errors (libm functions
- * should return a zero on underflow, and +- HUGE_VAL on
- * overflow, so testing the result for zero suffices to
- * distinguish the cases).
- *
- * On some platforms (Ubuntu/ia64) it seems that errno can be
- * set to ERANGE for subnormal results that do *not* underflow
- * to zero. So to be safe, we'll ignore ERANGE whenever the
- * function result is less than one in absolute value.
- */
- if (fabs(x) < 1.0)
- result = 0;
- else
- PyErr_SetString(PyExc_OverflowError,
- "math range error");
- }
- else
- /* Unexpected math error */
- PyErr_SetFromErrno(PyExc_ValueError);
- return result;
-}
-
-#ifdef HAVE_COPYSIGN
-/* only python >= 2.6 has the extra defs */
-
-/*
- wrapper for atan2 that deals directly with special cases before
- delegating to the platform libm for the remaining cases. This
- is necessary to get consistent behaviour across platforms.
- Windows, FreeBSD and alpha Tru64 are amongst platforms that don't
- always follow C99.
-*/
-
-static double
-m_atan2(double y, double x)
-{
- if (Py_IS_NAN(x) || Py_IS_NAN(y))
- return Py_NAN;
- if (Py_IS_INFINITY(y)) {
- if (Py_IS_INFINITY(x)) {
- if (copysign(1., x) == 1.)
- /* atan2(+-inf, +inf) == +-pi/4 */
- return copysign(0.25*Py_MATH_PI, y);
- else
- /* atan2(+-inf, -inf) == +-pi*3/4 */
- return copysign(0.75*Py_MATH_PI, y);
- }
- /* atan2(+-inf, x) == +-pi/2 for finite x */
- return copysign(0.5*Py_MATH_PI, y);
- }
- if (Py_IS_INFINITY(x) || y == 0.) {
- if (copysign(1., x) == 1.)
- /* atan2(+-y, +inf) = atan2(+-0, +x) = +-0. */
- return copysign(0., y);
- else
- /* atan2(+-y, -inf) = atan2(+-0., -x) = +-pi. */
- return copysign(Py_MATH_PI, y);
- }
- return atan2(y, x);
-}
-
-#else
-#define m_atan2 atan2
-#endif
-
-#define CIMPL_MATH_FUNC1(funcname, func, libfunc, can_overflow) \
- static int cimpl_math_##func(double a, double* result) { \
- errno = 0; \
- PyFPE_START_PROTECT(funcname, return -1) \
- *result = libfunc(a); \
- PyFPE_END_PROTECT(*result); \
- if (Py_IS_NAN(*result)) { \
- if (!Py_IS_NAN(a)) \
- errno = EDOM; \
- else \
- errno = 0; \
- } \
- else if (Py_IS_INFINITY(*result)) { \
- if (Py_IS_FINITE(a)) \
- errno = can_overflow ? ERANGE : EDOM; \
- else \
- errno = 0; \
- } \
- if (errno && is_error(*result)) \
- return -1; \
- return 0; \
+#define CIMPL_MATH_FUNC1(funcname, func, libfunc) \
+ static int cimpl_math_##func(double a, double* result) { \
+ errno = 0; \
+ PyFPE_START_PROTECT(funcname, return -1) \
+ *result = libfunc(a); \
+ PyFPE_END_PROTECT(*result); \
+ return 0; \
}
#define CIMPL_MATH_FUNC2(funcname, func, libfunc) \
static int cimpl_math_##func(double a, double b, double* result) { \
- errno = 0; \
- PyFPE_START_PROTECT(funcname, return -1) \
- *result = libfunc(a,b); \
- PyFPE_END_PROTECT(*result); \
- if (Py_IS_NAN(*result)) { \
- if (!Py_IS_NAN(a) && !Py_IS_NAN(b)) \
- errno = EDOM; \
- else \
- errno = 0; \
- } \
- else if (Py_IS_INFINITY(*result)) { \
- if (Py_IS_FINITE(a) && Py_IS_FINITE(b)) \
- errno = ERANGE; \
- else \
- errno = 0; \
- } \
- if (errno && is_error(*result)) \
- return -1; \
- return 0; \
+ errno = 0; \
+ PyFPE_START_PROTECT(funcname, return -1) \
+ *result = libfunc(a,b); \
+ PyFPE_END_PROTECT(*result); \
+ return 0; \
}
/*
@@ -266,157 +153,25 @@
}
/* the functions cimpl_math_sin() etc */
-CIMPL_MATH_FUNC1("acos", acos, acos, 0)
-CIMPL_MATH_FUNC1("asin", asin, asin, 0)
-CIMPL_MATH_FUNC1("atan", atan, atan, 0)
-CIMPL_MATH_FUNC2("atan2", atan2, m_atan2)
-CIMPL_MATH_FUNC1("ceil", ceil, ceil, 0)
-CIMPL_MATH_FUNC1("cos", cos, cos, 0)
-CIMPL_MATH_FUNC1("cosh", cosh, cosh, 1)
-CIMPL_MATH_FUNC1("exp", exp, exp, 1)
-CIMPL_MATH_FUNC1("fabs", fabs, fabs, 0)
-CIMPL_MATH_FUNC1("floor", floor, floor, 0)
-CIMPL_MATH_FUNC1("sin", sin, sin, 0)
-CIMPL_MATH_FUNC1("sinh", sinh, sinh, 1)
-CIMPL_MATH_FUNC1("sqrt", sqrt, sqrt, 0)
-CIMPL_MATH_FUNC1("tan", tan, tan, 0)
-CIMPL_MATH_FUNC1("tanh", tanh, tanh, 0)
-
-static int
-cimpl_math_fmod(double x, double y, double* result)
-{
- /* fmod(x, +/-Inf) returns x for finite x. */
- if (Py_IS_INFINITY(y) && Py_IS_FINITE(x)) {
- *result = x;
- return 0;
- }
- errno = 0;
- PyFPE_START_PROTECT("in math_fmod", return -1);
- *result = fmod(x, y);
- PyFPE_END_PROTECT(*result);
- if (Py_IS_NAN(*result)) {
- if (!Py_IS_NAN(x) && !Py_IS_NAN(y))
- errno = EDOM;
- else
- errno = 0;
- }
- if (errno && is_error(*result))
- return -1;
- return 0;
-}
-
-static int
-cimpl_math_hypot(double x, double y, double* result)
-{
- /* hypot(x, +/-Inf) returns Inf, even if x is a NaN. */
- if (Py_IS_INFINITY(x)) {
- *result = fabs(x);
- return 0;
- }
- if (Py_IS_INFINITY(y)) {
- *result = fabs(y);
- return 0;
- }
- errno = 0;
- PyFPE_START_PROTECT("in math_hypot", return -1);
- *result = hypot(x, y);
- PyFPE_END_PROTECT(*result);
- if (Py_IS_NAN(*result)) {
- if (!Py_IS_NAN(x) && !Py_IS_NAN(y))
- errno = EDOM;
- else
- errno = 0;
- }
- else if (Py_IS_INFINITY(*result)) {
- if (Py_IS_FINITE(x) && Py_IS_FINITE(y))
- errno = ERANGE;
- else
- errno = 0;
- }
- if (errno && is_error(*result))
- return -1;
- return 0;
-}
-
-#ifdef HAVE_COPYSIGN
-
-/* pow can't use math_2, but needs its own wrapper: the problem is
- that an infinite result can arise either as a result of overflow
- (in which case OverflowError should be raised) or as a result of
- e.g. 0.**-5. (for which ValueError needs to be raised.)
-*/
-
-static int
-cimpl_math_pow(double x, double y, double* result)
-{
- int odd_y;
-
- /* deal directly with IEEE specials, to cope with problems on various
- platforms whose semantics don't exactly match C99 */
- *result = 0.; /* silence compiler warning */
- if (!Py_IS_FINITE(x) || !Py_IS_FINITE(y)) {
- errno = 0;
- if (Py_IS_NAN(x))
- *result = y == 0. ? 1. : x; /* NaN**0 = 1 */
- else if (Py_IS_NAN(y))
- *result = 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.)
- *result = odd_y ? x : fabs(x);
- else if (y == 0.)
- *result = 1.;
- else /* y < 0. */
- *result = odd_y ? copysign(0., x) : 0.;
- }
- else if (Py_IS_INFINITY(y)) {
- if (fabs(x) == 1.0)
- *result = 1.;
- else if (y > 0. && fabs(x) > 1.0)
- *result = y;
- else if (y < 0. && fabs(x) < 1.0) {
- *result = -y; /* result is +inf */
- if (x == 0.) /* 0**-inf: divide-by-zero */
- errno = EDOM;
- }
- else
- *result = 0.;
- }
- }
- else {
- /* let libm handle finite**finite */
- errno = 0;
- PyFPE_START_PROTECT("in math_pow", return -1);
- *result = pow(x, y);
- PyFPE_END_PROTECT(*result);
- /* a NaN result should arise only from (-ve)**(finite
- non-integer); in this case we want to raise ValueError. */
- if (!Py_IS_FINITE(*result)) {
- if (Py_IS_NAN(*result)) {
- 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(*result)) {
- if (x == 0.)
- errno = EDOM;
- else
- errno = ERANGE;
- }
- }
- }
-
- if (errno && is_error(*result))
- return -1;
- return 0;
-}
-
-#else
-CIMPL_MATH_FUNC2("pow", pow, pow);
-#endif
+CIMPL_MATH_FUNC1("acos", acos, acos)
+CIMPL_MATH_FUNC1("asin", asin, asin)
+CIMPL_MATH_FUNC1("atan", atan, atan)
+CIMPL_MATH_FUNC2("atan2", atan2, atan2)
+CIMPL_MATH_FUNC1("ceil", ceil, ceil)
+CIMPL_MATH_FUNC1("cos", cos, cos)
+CIMPL_MATH_FUNC1("cosh", cosh, cosh)
+CIMPL_MATH_FUNC1("exp", exp, exp)
+CIMPL_MATH_FUNC1("fabs", fabs, fabs)
+CIMPL_MATH_FUNC1("floor", floor, floor)
+CIMPL_MATH_FUNC2("fmod", fmod, fmod)
+CIMPL_MATH_FUNC2("hypot", hypot, hypot)
+/*CIMPL_MATH_FUNC2("power", power, pow)*/
+CIMPL_MATH_FUNC2("pow", pow, pow)
+CIMPL_MATH_FUNC1("sin", sin, sin)
+CIMPL_MATH_FUNC1("sinh", sinh, sinh)
+CIMPL_MATH_FUNC1("sqrt", sqrt, sqrt)
+CIMPL_MATH_FUNC1("tan", tan, tan)
+CIMPL_MATH_FUNC1("tanh", tanh, tanh)
/* the functions pmath_sin() etc */
PMATH_FUNC1("acos", acos)
@@ -431,6 +186,7 @@
PMATH_FUNC1("floor", floor)
PMATH_FUNC2("fmod", fmod)
PMATH_FUNC2("hypot", hypot)
+/*PMATH_FUNC2("power", power)*/
PMATH_FUNC2("pow", pow)
PMATH_FUNC1("sin", sin)
PMATH_FUNC1("sinh", sinh)
@@ -461,6 +217,7 @@
fallback_floor= Psyco_DefineModuleFn(md, "floor",METH1, pmath_floor);
fallback_fmod = Psyco_DefineModuleFn(md, "fmod", METH_VARARGS, pmath_fmod);
fallback_hypot= Psyco_DefineModuleFn(md, "hypot",METH_VARARGS, pmath_hypot);
+ /*Psyco_DefineModuleFn(md, "power", METH_VARARGS, pmath_power);*/
fallback_pow = Psyco_DefineModuleFn(md, "pow", METH_VARARGS, pmath_pow);
fallback_sin = Psyco_DefineModuleFn(md, "sin", METH1, pmath_sin);
fallback_sinh = Psyco_DefineModuleFn(md, "sinh", METH1, pmath_sinh);
|