static PyObject * math_2(PyObject *args, double (*func) (double, double), char *funcname) { PyObject *ox, *oy; double x, y, r; if (! PyArg_UnpackTuple(args, funcname, 2, 2, &ox, &oy)) return NULL; x = PyFloat_AsDouble(ox); y = PyFloat_AsDouble(oy); if ((x == -1.0 || y == -1.0) && PyErr_Occurred()) return NULL; errno = 0; PyFPE_START_PROTECT("in math_2", return 0); r = (*func)(x, y); PyFPE_END_PROTECT(r); if (Py_IS_NAN(r)) { if (!Py_IS_NAN(x) && !Py_IS_NAN(y)) errno = EDOM; else errno = 0; } else if (Py_IS_INFINITY(r)) { if (Py_IS_FINITE(x) && Py_IS_FINITE(y)) errno = ERANGE; else errno = 0; } if (errno && is_error(r)) return NULL; else return PyFloat_FromDouble(r); }
double c_abs(Py_complex z) { /* sets errno = ERANGE on overflow; otherwise errno = 0 */ double result; if (!Py_IS_FINITE(z.real) || !Py_IS_FINITE(z.imag)) { /* C99 rules: if either the real or the imaginary part is an infinity, return infinity, even if the other part is a NaN. */ if (Py_IS_INFINITY(z.real)) { result = fabs(z.real); errno = 0; return result; } if (Py_IS_INFINITY(z.imag)) { result = fabs(z.imag); errno = 0; return result; } /* either the real or imaginary part is a NaN, and neither is infinite. Result should be NaN. */ return Py_NAN; } result = hypot(z.real, z.imag); if (!Py_IS_FINITE(result)) errno = ERANGE; else errno = 0; return result; }
static PyObject * math_1_to_whatever(PyObject *arg, double (*func) (double), PyObject *(*from_double_func) (double), int can_overflow) { double x, r; x = PyFloat_AsDouble(arg); if (x == -1.0 && PyErr_Occurred()) return NULL; errno = 0; PyFPE_START_PROTECT("in math_1", return 0); r = (*func)(x); PyFPE_END_PROTECT(r); if (Py_IS_NAN(r) && !Py_IS_NAN(x)) { PyErr_SetString(PyExc_ValueError, "math domain error"); /* invalid arg */ return NULL; } if (Py_IS_INFINITY(r) && Py_IS_FINITE(x)) { if (can_overflow) PyErr_SetString(PyExc_OverflowError, "math range error"); /* overflow */ else PyErr_SetString(PyExc_ValueError, "math domain error"); /* singularity */ return NULL; } if (Py_IS_FINITE(r) && errno && is_error(r)) /* this branch unnecessary on most platforms */ return NULL; return (*from_double_func)(r); }
static PyObject * complex_is_finite(PyObject *self) { Py_complex c; c = ((PyComplexObject *)self)->cval; return PyBool_FromLong((long)(Py_IS_FINITE(c.real) && Py_IS_FINITE(c.imag))); }
static void complex_to_buf(char *buf, int bufsz, PyComplexObject *v, int precision) { char format[32]; if (v->cval.real == 0.) { if (!Py_IS_FINITE(v->cval.imag)) { if (Py_IS_NAN(v->cval.imag)) strncpy(buf, "nan*j", 6); else if (copysign(1, v->cval.imag) == 1) strncpy(buf, "inf*j", 6); else strncpy(buf, "-inf*j", 7); } else { PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); PyOS_ascii_formatd(buf, bufsz - 1, format, v->cval.imag); strncat(buf, "j", 1); } } else { char re[64], im[64]; /* Format imaginary part with sign, real part without */ if (!Py_IS_FINITE(v->cval.real)) { if (Py_IS_NAN(v->cval.real)) strncpy(re, "nan", 4); /* else if (copysign(1, v->cval.real) == 1) */ else if (v->cval.real > 0) strncpy(re, "inf", 4); else strncpy(re, "-inf", 5); } else { PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); PyOS_ascii_formatd(re, sizeof(re), format, v->cval.real); } if (!Py_IS_FINITE(v->cval.imag)) { if (Py_IS_NAN(v->cval.imag)) strncpy(im, "+nan*", 6); /* else if (copysign(1, v->cval.imag) == 1) */ else if (v->cval.imag > 0) strncpy(im, "+inf*", 6); else strncpy(im, "-inf*", 6); } else { PyOS_snprintf(format, sizeof(format), "%%+.%ig", precision); PyOS_ascii_formatd(im, sizeof(im), format, v->cval.imag); } PyOS_snprintf(buf, bufsz, "(%s%sj)", re, im); } }
static PyObject * math_fmod(PyObject *self, PyObject *args) { PyObject *ox, *oy; double r, x, y; if (! PyArg_UnpackTuple(args, "fmod", 2, 2, &ox, &oy)) return NULL; x = PyFloat_AsDouble(ox); y = PyFloat_AsDouble(oy); if ((x == -1.0 || y == -1.0) && PyErr_Occurred()) return NULL; /* fmod(x, +/-Inf) returns x for finite x. */ if (Py_IS_INFINITY(y) && Py_IS_FINITE(x)) return PyFloat_FromDouble(x); errno = 0; PyFPE_START_PROTECT("in math_fmod", return 0); r = fmod(x, y); PyFPE_END_PROTECT(r); if (Py_IS_NAN(r)) { if (!Py_IS_NAN(x) && !Py_IS_NAN(y)) errno = EDOM; else errno = 0; } if (errno && is_error(r)) return NULL; else return PyFloat_FromDouble(r); }
static PyObject * math_hypot(PyObject *self, PyObject *args) { PyObject *ox, *oy; double r, x, y; if (! PyArg_UnpackTuple(args, "hypot", 2, 2, &ox, &oy)) return NULL; x = PyFloat_AsDouble(ox); y = PyFloat_AsDouble(oy); if ((x == -1.0 || y == -1.0) && PyErr_Occurred()) return NULL; /* hypot(x, +/-Inf) returns Inf, even if x is a NaN. */ if (Py_IS_INFINITY(x)) return PyFloat_FromDouble(fabs(x)); if (Py_IS_INFINITY(y)) return PyFloat_FromDouble(fabs(y)); errno = 0; PyFPE_START_PROTECT("in math_hypot", return 0); r = hypot(x, y); PyFPE_END_PROTECT(r); if (Py_IS_NAN(r)) { if (!Py_IS_NAN(x) && !Py_IS_NAN(y)) errno = EDOM; else errno = 0; } else if (Py_IS_INFINITY(r)) { if (Py_IS_FINITE(x) && Py_IS_FINITE(y)) errno = ERANGE; else errno = 0; } if (errno && is_error(r)) return NULL; else return PyFloat_FromDouble(r); }
static PyObject * math_modf(PyObject *self, PyObject *arg) { double y, x = PyFloat_AsDouble(arg); if (x == -1.0 && PyErr_Occurred()) return NULL; /* some platforms don't do the right thing for NaNs and infinities, so we take care of special cases directly. */ if (!Py_IS_FINITE(x)) { if (Py_IS_INFINITY(x)) return Py_BuildValue("(dd)", copysign(0., x), x); else if (Py_IS_NAN(x)) return Py_BuildValue("(dd)", x, x); } errno = 0; PyFPE_START_PROTECT("in math_modf", return 0); x = modf(x, &y); PyFPE_END_PROTECT(x); return Py_BuildValue("(dd)", x, y); }
static PyObject * math_pow(PyObject *self, PyObject *args) { PyObject *ox, *oy; double r, x, y; int odd_y; if (! PyArg_UnpackTuple(args, "pow", 2, 2, &ox, &oy)) return NULL; x = PyFloat_AsDouble(ox); y = PyFloat_AsDouble(oy); if ((x == -1.0 || y == -1.0) && PyErr_Occurred()) return NULL; /* deal directly with IEEE specials, to cope with problems on various platforms whose semantics don't exactly match C99 */ r = 0.; /* silence compiler warning */ 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.; } } 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)) return NULL; else return PyFloat_FromDouble(r); }
static PyObject * math_ldexp(PyObject *self, PyObject *args) { double x, r; PyObject *oexp; long exp; if (! PyArg_ParseTuple(args, "dO:ldexp", &x, &oexp)) return NULL; if (PyLong_Check(oexp)) { /* on overflow, replace exponent with either LONG_MAX or LONG_MIN, depending on the sign. */ exp = PyLong_AsLong(oexp); if (exp == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { if (Py_SIZE(oexp) < 0) { exp = LONG_MIN; } else { exp = LONG_MAX; } PyErr_Clear(); } else { /* propagate any unexpected exception */ return NULL; } } } else { PyErr_SetString(PyExc_TypeError, "Expected an int or long as second argument " "to ldexp."); return NULL; } if (x == 0. || !Py_IS_FINITE(x)) { /* NaNs, zeros and infinities are returned unchanged */ r = x; errno = 0; } else if (exp > INT_MAX) { /* overflow */ r = copysign(Py_HUGE_VAL, x); errno = ERANGE; } else if (exp < INT_MIN) { /* underflow to +-0 */ r = copysign(0., x); errno = 0; } else { errno = 0; PyFPE_START_PROTECT("in math_ldexp", return 0); r = ldexp(x, (int)exp); PyFPE_END_PROTECT(r); if (Py_IS_INFINITY(r)) errno = ERANGE; } if (errno && is_error(r)) return NULL; return PyFloat_FromDouble(r); }
static PyObject* math_fsum(PyObject *self, PyObject *seq) { PyObject *item, *iter, *sum = NULL; Py_ssize_t i, j, n = 0, m = NUM_PARTIALS; double x, y, t, ps[NUM_PARTIALS], *p = ps; double xsave, special_sum = 0.0, inf_sum = 0.0; volatile double hi, yr, lo; iter = PyObject_GetIter(seq); if (iter == NULL) return NULL; PyFPE_START_PROTECT("fsum", Py_DECREF(iter); return NULL) for(;;) { /* for x in iterable */ assert(0 <= n && n <= m); assert((m == NUM_PARTIALS && p == ps) || (m > NUM_PARTIALS && p != NULL)); item = PyIter_Next(iter); if (item == NULL) { if (PyErr_Occurred()) goto _fsum_error; break; } x = PyFloat_AsDouble(item); Py_DECREF(item); if (PyErr_Occurred()) goto _fsum_error; xsave = x; for (i = j = 0; j < n; j++) { /* for y in partials */ y = p[j]; if (fabs(x) < fabs(y)) { t = x; x = y; y = t; } hi = x + y; yr = hi - x; lo = y - yr; if (lo != 0.0) p[i++] = lo; x = hi; } n = i; /* ps[i:] = [x] */ if (x != 0.0) { if (! Py_IS_FINITE(x)) { /* a nonfinite x could arise either as a result of intermediate overflow, or as a result of a nan or inf in the summands */ if (Py_IS_FINITE(xsave)) { PyErr_SetString(PyExc_OverflowError, "intermediate overflow in fsum"); goto _fsum_error; } if (Py_IS_INFINITY(xsave)) inf_sum += xsave; special_sum += xsave; /* reset partials */ n = 0; } else if (n >= m && _fsum_realloc(&p, n, ps, &m)) goto _fsum_error; else p[n++] = x; } } if (special_sum != 0.0) { if (Py_IS_NAN(inf_sum)) PyErr_SetString(PyExc_ValueError, "-inf + inf in fsum"); else sum = PyFloat_FromDouble(special_sum); goto _fsum_error; } hi = 0.0; if (n > 0) { hi = p[--n]; /* sum_exact(ps, hi) from the top, stop when the sum becomes inexact. */ while (n > 0) { x = hi; y = p[--n]; assert(fabs(y) < fabs(x)); hi = x + y; yr = hi - x; lo = y - yr; if (lo != 0.0) break; } /* Make half-even rounding work across multiple partials. Needed so that sum([1e-16, 1, 1e16]) will round-up the last digit to two instead of down to zero (the 1e-16 makes the 1 slightly closer to two). With a potential 1 ULP rounding error fixed-up, math.fsum() can guarantee commutativity. */ if (n > 0 && ((lo < 0.0 && p[n-1] < 0.0) || (lo > 0.0 && p[n-1] > 0.0))) { y = lo * 2.0; x = hi + y; yr = x - hi; if (y == yr) hi = x; } } sum = PyFloat_FromDouble(hi); _fsum_error: PyFPE_END_PROTECT(hi) Py_DECREF(iter); if (p != ps) PyMem_Free(p); return sum; }