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 * complex_pow(PyComplexObject *v, PyObject *w, PyComplexObject *z) { Py_complex p; Py_complex exponent; long int_exponent; if ((PyObject *)z!=Py_None) { PyErr_SetString(PyExc_ValueError, "complex modulo"); return NULL; } PyFPE_START_PROTECT("complex_pow", return 0) errno = 0; exponent = ((PyComplexObject*)w)->cval; int_exponent = (long)exponent.real; if (exponent.imag == 0. && exponent.real == int_exponent) p = c_powi(v->cval,int_exponent); else p = c_pow(v->cval,exponent); PyFPE_END_PROTECT(p) Py_ADJUST_ERANGE2(p.real, p.imag); if (errno == EDOM) { PyErr_SetString(PyExc_ZeroDivisionError, "0.0 to a negative or complex power"); return NULL; } else if (errno == ERANGE) { PyErr_SetString(PyExc_OverflowError, "complex exponentiation"); return NULL; } return PyComplex_FromCComplex(p); }
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); }
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 bool FLOAT_ADD_INCREMENTAL(PyObject **operand1, PyObject *operand2) { assert(PyFloat_CheckExact(*operand1)); assert(PyFloat_CheckExact(operand2)); PyFPE_START_PROTECT("add", return false); PyFloat_AS_DOUBLE(*operand1) += PyFloat_AS_DOUBLE(operand2); PyFPE_END_PROTECT(*operand1); return true; }
static PyObject * math_1(PyObject *args, Py_complex (*func)(Py_complex)) { Py_complex x; if (!PyArg_ParseTuple(args, "D", &x)) return NULL; errno = 0; PyFPE_START_PROTECT("complex function", return 0) x = (*func)(x); PyFPE_END_PROTECT(x) Py_ADJUST_ERANGE2(x.real, x.imag); if (errno != 0) return math_error(); else return PyComplex_FromCComplex(x); }
static PyObject * math_1(PyObject *args, double (*func) (double), char *argsfmt) { double x; if (! PyArg_ParseTuple(args, argsfmt, &x)) return NULL; errno = 0; PyFPE_START_PROTECT("in math_1", return 0) x = (*func)(x); PyFPE_END_PROTECT(x) Py_SET_ERANGE_IF_OVERFLOW(x); if (errno && is_error(x)) return NULL; else return PyFloat_FromDouble(x); }
static PyObject * math_2(PyObject *args, double (*func) (double, double), char *argsfmt) { double x, y; if (! PyArg_ParseTuple(args, argsfmt, &x, &y)) return NULL; errno = 0; PyFPE_START_PROTECT("in math_2", return 0) x = (*func)(x, y); PyFPE_END_PROTECT(x) Py_SET_ERRNO_ON_MATH_ERROR(x); if (errno && is_error(x)) return NULL; else return PyFloat_FromDouble(x); }
static PyObject * math_ldexp(PyObject *self, PyObject *args) { double x; int exp; if (! PyArg_ParseTuple(args, "di:ldexp", &x, &exp)) return NULL; errno = 0; PyFPE_START_PROTECT("ldexp", return 0) x = ldexp(x, exp); PyFPE_END_PROTECT(x) Py_SET_ERANGE_IF_OVERFLOW(x); if (errno && is_error(x)) return NULL; else return PyFloat_FromDouble(x); }
static PyObject * math_frexp(PyObject *self, PyObject *arg) { int i; double x = PyFloat_AsDouble(arg); if (x == -1.0 && PyErr_Occurred()) return NULL; /* deal with special cases directly, to sidestep platform differences */ if (Py_IS_NAN(x) || Py_IS_INFINITY(x) || !x) { i = 0; } else { PyFPE_START_PROTECT("in math_frexp", return 0); x = frexp(x, &i); PyFPE_END_PROTECT(x); } return Py_BuildValue("(di)", x, i); }
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_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 *bip_sum(term_t t) { PyObject *seq; PyObject *result = NULL; PyObject *temp, *item, *iter; if (!PL_get_arg(1, t, t)) return NULL; seq = term_to_python(t, true); iter = PyObject_GetIter(seq); if (iter == NULL) return NULL; if (result == NULL) { #if PY_MAJOR_VERSION < 3 result = PyInt_FromLong(0); #else result = PyLong_FromLong(0); #endif if (result == NULL) { Py_DECREF(iter); return NULL; } } else { #if PY_MAJOR_VERSION < 3 /* reject string values for 'start' parameter */ if (PyObject_TypeCheck(result, &PyBaseString_Type)) { PyErr_SetString(PyExc_TypeError, "sum() can't sum strings [use ''.join(seq) instead]"); Py_DECREF(iter); return NULL; } Py_INCREF(result); #endif } #ifndef SLOW_SUM /* Fast addition by keeping temporary sums in C instead of new Python objects. Assumes all inputs are the same type. If the assumption fails, default to the more general routine. */ #if PY_MAJOR_VERSION < 3 if (PyInt_CheckExact(result)) { long i_result = PyInt_AS_LONG(result); #else if (PyLong_CheckExact(result)) { long i_result = PyLong_AS_LONG(result); #endif Py_DECREF(result); result = NULL; while (result == NULL) { item = PyIter_Next(iter); if (item == NULL) { Py_DECREF(iter); if (PyErr_Occurred()) return NULL; #if PY_MAJOR_VERSION < 3 return PyInt_FromLong(i_result); #else return PyLong_FromLong(i_result); #endif } #if PY_MAJOR_VERSION < 3 if (PyInt_CheckExact(item)) { long b = PyInt_AS_LONG(item); #else if (PyLong_CheckExact(item)) { long b = PyLong_AS_LONG(item); #endif long x = i_result + b; if ((x ^ i_result) >= 0 || (x ^ b) >= 0) { i_result = x; Py_DECREF(item); continue; } } /* Either overflowed or is not an int. Restore real objects and process normally */ #if PY_MAJOR_VERSION < 3 result = PyInt_FromLong(i_result); #else result = PyLong_FromLong(i_result); #endif temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); result = temp; if (result == NULL) { Py_DECREF(iter); return NULL; } } } if (PyFloat_CheckExact(result)) { double f_result = PyFloat_AS_DOUBLE(result); Py_DECREF(result); result = NULL; while (result == NULL) { item = PyIter_Next(iter); if (item == NULL) { Py_DECREF(iter); if (PyErr_Occurred()) return NULL; return PyFloat_FromDouble(f_result); } if (PyFloat_CheckExact(item)) { PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) f_result += PyFloat_AS_DOUBLE(item); PyFPE_END_PROTECT(f_result) Py_DECREF(item); continue; } #if PY_MAJOR_VERSION < 3 if (PyInt_CheckExact(item)) { PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) f_result += (double)PyInt_AS_LONG(item); PyFPE_END_PROTECT(f_result) Py_DECREF(item); continue; } #else if (PyLong_CheckExact(item)) { PyFPE_START_PROTECT("add", Py_DECREF(item); Py_DECREF(iter); return 0) f_result += PyLong_AsDouble(item); PyFPE_END_PROTECT(f_result) Py_DECREF(item); continue; } #endif result = PyFloat_FromDouble(f_result); temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); result = temp; if (result == NULL) { Py_DECREF(iter); return NULL; } } #endif } for (;;) { item = PyIter_Next(iter); if (item == NULL) { /* error, or end-of-sequence */ if (PyErr_Occurred()) { Py_DECREF(result); result = NULL; } break; } /* It's tempting to use PyNumber_InPlaceAdd instead of PyNumber_Add here, to avoid quadratic running time when doing 'sum(list_of_lists, [])'. However, this would produce a change in behaviour: a snippet like empty = [] sum([[x] for x in range(10)], empty) would change the value of empty. */ temp = PyNumber_Add(result, item); Py_DECREF(result); Py_DECREF(item); result = temp; if (result == NULL) break; } Py_DECREF(iter); return result; } //@} static long get_int(term_t arg, bool eval) { long low; if (!PL_get_long(arg, &low)) { PyObject *low = term_to_python(arg, eval); if (PyLong_Check(low)) { return PyLong_AsLong(low); #if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(low)) { return PyInt_AsLong(low); #endif } else { return 0; } } return low; } /* Return number of items in range/xrange (lo, hi, step). step > 0 * required. Return a value < 0 if & only if the true value is too * large to fit in a signed long. */ static long get_len_of_range(long lo, long hi, long step) { /* ------------------------------------------------------------- If lo >= hi, the range is empty. Else if n values are in the range, the last one is lo + (n-1)*step, which must be <= hi-1. Rearranging, n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so the RHS is non-negative and so truncation is the same as the floor. Letting M be the largest positive long, the worst case for the RHS numerator is hi=M, lo=-M-1, and then hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough precision to compute the RHS exactly. ---------------------------------------------------------------*/ long n = 0; if (lo < hi) { unsigned long uhi = (unsigned long)hi; unsigned long ulo = (unsigned long)lo; unsigned long diff = uhi - ulo - 1; n = (long)(diff / (unsigned long)step + 1); } return n; }
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; }