Rename math.sum to math.fsum

This commit is contained in:
Mark Dickinson 2008-07-30 16:20:10 +00:00
parent f2eb2b44fc
commit fef6b13c32
5 changed files with 35 additions and 35 deletions

View File

@ -83,6 +83,16 @@ Number-theoretic and representation functions:
apart" the internal representation of a float in a portable way. apart" the internal representation of a float in a portable way.
.. function:: fsum(iterable)
Return an accurate floating point sum of values in the iterable. Avoids
loss of precision by tracking multiple intermediate partial sums. The
algorithm's accuracy depends on IEEE-754 arithmetic guarantees and the
typical case where the rounding mode is half-even.
.. versionadded:: 2.6
.. function:: isinf(x) .. function:: isinf(x)
Checks if the float *x* is positive or negative infinite. Checks if the float *x* is positive or negative infinite.
@ -112,16 +122,6 @@ Number-theoretic and representation functions:
*x*, and both are floats. *x*, and both are floats.
.. function:: sum(iterable)
Return an accurate floating point sum of values in the iterable. Avoids
loss of precision by tracking multiple intermediate partial sums. The
algorithm's accuracy depends on IEEE-754 arithmetic guarantees and the
typical case where the rounding mode is half-even.
.. versionadded:: 2.6
.. function:: trunc(x) .. function:: trunc(x)
Return the :class:`Real` value *x* truncated to an :class:`Integral` (usually Return the :class:`Real` value *x* truncated to an :class:`Integral` (usually

View File

@ -1537,7 +1537,7 @@ Here are all of the changes that Python 2.6 makes to the core Python language.
* :func:`~math.factorial` computes the factorial of a number. * :func:`~math.factorial` computes the factorial of a number.
(Contributed by Raymond Hettinger; :issue:`2138`.) (Contributed by Raymond Hettinger; :issue:`2138`.)
* :func:`~math.sum` adds up the stream of numbers from an iterable, * :func:`~math.fsum` adds up the stream of numbers from an iterable,
and is careful to avoid loss of precision by calculating partial sums. and is careful to avoid loss of precision by calculating partial sums.
(Contributed by Jean Brouwers, Raymond Hettinger, and Mark Dickinson; (Contributed by Jean Brouwers, Raymond Hettinger, and Mark Dickinson;
:issue:`2819`.) :issue:`2819`.)

View File

@ -646,10 +646,10 @@ class MathTests(unittest.TestCase):
self.assert_(math.isnan(math.sqrt(NAN))) self.assert_(math.isnan(math.sqrt(NAN)))
def testSum(self): def testSum(self):
# math.sum relies on exact rounding for correct operation. # math.fsum relies on exact rounding for correct operation.
# There's a known problem with IA32 floating-point that causes # There's a known problem with IA32 floating-point that causes
# inexact rounding in some situations, and will cause the # inexact rounding in some situations, and will cause the
# math.sum tests below to fail; see issue #2937. On non IEEE # math.fsum tests below to fail; see issue #2937. On non IEEE
# 754 platforms, and on IEEE 754 platforms that exhibit the # 754 platforms, and on IEEE 754 platforms that exhibit the
# problem described in issue #2937, we simply skip the whole # problem described in issue #2937, we simply skip the whole
# test. # test.
@ -662,7 +662,7 @@ class MathTests(unittest.TestCase):
if 1e16+2.0 != 1e16+2.9999: if 1e16+2.0 != 1e16+2.9999:
return return
# Python version of math.sum, for comparison. Uses a # Python version of math.fsum, for comparison. Uses a
# different algorithm based on frexp, ldexp and integer # different algorithm based on frexp, ldexp and integer
# arithmetic. # arithmetic.
from sys import float_info from sys import float_info
@ -719,13 +719,13 @@ class MathTests(unittest.TestCase):
for i, (vals, expected) in enumerate(test_values): for i, (vals, expected) in enumerate(test_values):
try: try:
actual = math.sum(vals) actual = math.fsum(vals)
except OverflowError: except OverflowError:
self.fail("test %d failed: got OverflowError, expected %r " self.fail("test %d failed: got OverflowError, expected %r "
"for math.sum(%.100r)" % (i, expected, vals)) "for math.fsum(%.100r)" % (i, expected, vals))
except ValueError: except ValueError:
self.fail("test %d failed: got ValueError, expected %r " self.fail("test %d failed: got ValueError, expected %r "
"for math.sum(%.100r)" % (i, expected, vals)) "for math.fsum(%.100r)" % (i, expected, vals))
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
from random import random, gauss, shuffle from random import random, gauss, shuffle
@ -739,7 +739,7 @@ class MathTests(unittest.TestCase):
shuffle(vals) shuffle(vals)
s = msum(vals) s = msum(vals)
self.assertEqual(msum(vals), math.sum(vals)) self.assertEqual(msum(vals), math.fsum(vals))
def testTan(self): def testTan(self):

View File

@ -5,7 +5,7 @@ import random
import time import time
import pickle import pickle
import warnings import warnings
from math import log, exp, sqrt, pi, sum as msum from math import log, exp, sqrt, pi, fsum as msum
from test import test_support from test import test_support
class TestBasicOps(unittest.TestCase): class TestBasicOps(unittest.TestCase):

View File

@ -352,7 +352,7 @@ FUNC1(tanh, tanh, 0,
/* Extend the partials array p[] by doubling its size. */ /* Extend the partials array p[] by doubling its size. */
static int /* non-zero on error */ static int /* non-zero on error */
_sum_realloc(double **p_ptr, Py_ssize_t n, _fsum_realloc(double **p_ptr, Py_ssize_t n,
double *ps, Py_ssize_t *m_ptr) double *ps, Py_ssize_t *m_ptr)
{ {
void *v = NULL; void *v = NULL;
@ -370,7 +370,7 @@ _sum_realloc(double **p_ptr, Py_ssize_t n,
v = PyMem_Realloc(p, sizeof(double) * m); v = PyMem_Realloc(p, sizeof(double) * m);
} }
if (v == NULL) { /* size overflow or no memory */ if (v == NULL) { /* size overflow or no memory */
PyErr_SetString(PyExc_MemoryError, "math sum partials"); PyErr_SetString(PyExc_MemoryError, "math.fsum partials");
return 1; return 1;
} }
*p_ptr = (double*) v; *p_ptr = (double*) v;
@ -409,7 +409,7 @@ _sum_realloc(double **p_ptr, Py_ssize_t n,
*/ */
static PyObject* static PyObject*
math_sum(PyObject *self, PyObject *seq) math_fsum(PyObject *self, PyObject *seq)
{ {
PyObject *item, *iter, *sum = NULL; PyObject *item, *iter, *sum = NULL;
Py_ssize_t i, j, n = 0, m = NUM_PARTIALS; Py_ssize_t i, j, n = 0, m = NUM_PARTIALS;
@ -421,7 +421,7 @@ math_sum(PyObject *self, PyObject *seq)
if (iter == NULL) if (iter == NULL)
return NULL; return NULL;
PyFPE_START_PROTECT("sum", Py_DECREF(iter); return NULL) PyFPE_START_PROTECT("fsum", Py_DECREF(iter); return NULL)
for(;;) { /* for x in iterable */ for(;;) { /* for x in iterable */
assert(0 <= n && n <= m); assert(0 <= n && n <= m);
@ -431,13 +431,13 @@ math_sum(PyObject *self, PyObject *seq)
item = PyIter_Next(iter); item = PyIter_Next(iter);
if (item == NULL) { if (item == NULL) {
if (PyErr_Occurred()) if (PyErr_Occurred())
goto _sum_error; goto _fsum_error;
break; break;
} }
x = PyFloat_AsDouble(item); x = PyFloat_AsDouble(item);
Py_DECREF(item); Py_DECREF(item);
if (PyErr_Occurred()) if (PyErr_Occurred())
goto _sum_error; goto _fsum_error;
xsave = x; xsave = x;
for (i = j = 0; j < n; j++) { /* for y in partials */ for (i = j = 0; j < n; j++) { /* for y in partials */
@ -462,8 +462,8 @@ math_sum(PyObject *self, PyObject *seq)
summands */ summands */
if (Py_IS_FINITE(xsave)) { if (Py_IS_FINITE(xsave)) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"intermediate overflow in sum"); "intermediate overflow in fsum");
goto _sum_error; goto _fsum_error;
} }
if (Py_IS_INFINITY(xsave)) if (Py_IS_INFINITY(xsave))
inf_sum += xsave; inf_sum += xsave;
@ -471,8 +471,8 @@ math_sum(PyObject *self, PyObject *seq)
/* reset partials */ /* reset partials */
n = 0; n = 0;
} }
else if (n >= m && _sum_realloc(&p, n, ps, &m)) else if (n >= m && _fsum_realloc(&p, n, ps, &m))
goto _sum_error; goto _fsum_error;
else else
p[n++] = x; p[n++] = x;
} }
@ -481,10 +481,10 @@ math_sum(PyObject *self, PyObject *seq)
if (special_sum != 0.0) { if (special_sum != 0.0) {
if (Py_IS_NAN(inf_sum)) if (Py_IS_NAN(inf_sum))
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"-inf + inf in sum"); "-inf + inf in fsum");
else else
sum = PyFloat_FromDouble(special_sum); sum = PyFloat_FromDouble(special_sum);
goto _sum_error; goto _fsum_error;
} }
hi = 0.0; hi = 0.0;
@ -518,7 +518,7 @@ math_sum(PyObject *self, PyObject *seq)
} }
sum = PyFloat_FromDouble(hi); sum = PyFloat_FromDouble(hi);
_sum_error: _fsum_error:
PyFPE_END_PROTECT(hi) PyFPE_END_PROTECT(hi)
Py_DECREF(iter); Py_DECREF(iter);
if (p != ps) if (p != ps)
@ -528,7 +528,7 @@ _sum_error:
#undef NUM_PARTIALS #undef NUM_PARTIALS
PyDoc_STRVAR(math_sum_doc, PyDoc_STRVAR(math_fsum_doc,
"sum(iterable)\n\n\ "sum(iterable)\n\n\
Return an accurate floating point sum of values in the iterable.\n\ Return an accurate floating point sum of values in the iterable.\n\
Assumes IEEE-754 floating point arithmetic."); Assumes IEEE-754 floating point arithmetic.");
@ -1021,6 +1021,7 @@ static PyMethodDef math_methods[] = {
{"floor", math_floor, METH_O, math_floor_doc}, {"floor", math_floor, METH_O, math_floor_doc},
{"fmod", math_fmod, METH_VARARGS, math_fmod_doc}, {"fmod", math_fmod, METH_VARARGS, math_fmod_doc},
{"frexp", math_frexp, METH_O, math_frexp_doc}, {"frexp", math_frexp, METH_O, math_frexp_doc},
{"fsum", math_fsum, METH_O, math_fsum_doc},
{"hypot", math_hypot, METH_VARARGS, math_hypot_doc}, {"hypot", math_hypot, METH_VARARGS, math_hypot_doc},
{"isinf", math_isinf, METH_O, math_isinf_doc}, {"isinf", math_isinf, METH_O, math_isinf_doc},
{"isnan", math_isnan, METH_O, math_isnan_doc}, {"isnan", math_isnan, METH_O, math_isnan_doc},
@ -1034,7 +1035,6 @@ static PyMethodDef math_methods[] = {
{"sin", math_sin, METH_O, math_sin_doc}, {"sin", math_sin, METH_O, math_sin_doc},
{"sinh", math_sinh, METH_O, math_sinh_doc}, {"sinh", math_sinh, METH_O, math_sinh_doc},
{"sqrt", math_sqrt, METH_O, math_sqrt_doc}, {"sqrt", math_sqrt, METH_O, math_sqrt_doc},
{"sum", math_sum, METH_O, math_sum_doc},
{"tan", math_tan, METH_O, math_tan_doc}, {"tan", math_tan, METH_O, math_tan_doc},
{"tanh", math_tanh, METH_O, math_tanh_doc}, {"tanh", math_tanh, METH_O, math_tanh_doc},
{"trunc", math_trunc, METH_O, math_trunc_doc}, {"trunc", math_trunc, METH_O, math_trunc_doc},