From fef6b13c3261b9c91d38247f5ff99a411d71ab13 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Wed, 30 Jul 2008 16:20:10 +0000 Subject: [PATCH] Rename math.sum to math.fsum --- Doc/library/math.rst | 20 ++++++++++---------- Doc/whatsnew/2.6.rst | 2 +- Lib/test/test_math.py | 14 +++++++------- Lib/test/test_random.py | 2 +- Modules/mathmodule.c | 32 ++++++++++++++++---------------- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Doc/library/math.rst b/Doc/library/math.rst index 61a6fd6df17..574075933b5 100644 --- a/Doc/library/math.rst +++ b/Doc/library/math.rst @@ -83,6 +83,16 @@ Number-theoretic and representation functions: 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) Checks if the float *x* is positive or negative infinite. @@ -112,16 +122,6 @@ Number-theoretic and representation functions: *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) Return the :class:`Real` value *x* truncated to an :class:`Integral` (usually diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index a8d89cb1a9e..9959ecd74cc 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -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. (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. (Contributed by Jean Brouwers, Raymond Hettinger, and Mark Dickinson; :issue:`2819`.) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 09f884ee2d5..9f5fdbab5bd 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -646,10 +646,10 @@ class MathTests(unittest.TestCase): self.assert_(math.isnan(math.sqrt(NAN))) 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 # 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 # problem described in issue #2937, we simply skip the whole # test. @@ -662,7 +662,7 @@ class MathTests(unittest.TestCase): if 1e16+2.0 != 1e16+2.9999: 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 # arithmetic. from sys import float_info @@ -719,13 +719,13 @@ class MathTests(unittest.TestCase): for i, (vals, expected) in enumerate(test_values): try: - actual = math.sum(vals) + actual = math.fsum(vals) except OverflowError: 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: 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) from random import random, gauss, shuffle @@ -739,7 +739,7 @@ class MathTests(unittest.TestCase): shuffle(vals) s = msum(vals) - self.assertEqual(msum(vals), math.sum(vals)) + self.assertEqual(msum(vals), math.fsum(vals)) def testTan(self): diff --git a/Lib/test/test_random.py b/Lib/test/test_random.py index 8ad701b448d..4d570d07288 100644 --- a/Lib/test/test_random.py +++ b/Lib/test/test_random.py @@ -5,7 +5,7 @@ import random import time import pickle 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 class TestBasicOps(unittest.TestCase): diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index e481d305e6b..ef33dabec86 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -352,7 +352,7 @@ FUNC1(tanh, tanh, 0, /* Extend the partials array p[] by doubling its size. */ 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) { void *v = NULL; @@ -370,7 +370,7 @@ _sum_realloc(double **p_ptr, Py_ssize_t n, v = PyMem_Realloc(p, sizeof(double) * m); } if (v == NULL) { /* size overflow or no memory */ - PyErr_SetString(PyExc_MemoryError, "math sum partials"); + PyErr_SetString(PyExc_MemoryError, "math.fsum partials"); return 1; } *p_ptr = (double*) v; @@ -409,7 +409,7 @@ _sum_realloc(double **p_ptr, Py_ssize_t n, */ static PyObject* -math_sum(PyObject *self, PyObject *seq) +math_fsum(PyObject *self, PyObject *seq) { PyObject *item, *iter, *sum = NULL; Py_ssize_t i, j, n = 0, m = NUM_PARTIALS; @@ -421,7 +421,7 @@ math_sum(PyObject *self, PyObject *seq) if (iter == 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 */ assert(0 <= n && n <= m); @@ -431,13 +431,13 @@ math_sum(PyObject *self, PyObject *seq) item = PyIter_Next(iter); if (item == NULL) { if (PyErr_Occurred()) - goto _sum_error; + goto _fsum_error; break; } x = PyFloat_AsDouble(item); Py_DECREF(item); if (PyErr_Occurred()) - goto _sum_error; + goto _fsum_error; xsave = x; for (i = j = 0; j < n; j++) { /* for y in partials */ @@ -462,8 +462,8 @@ math_sum(PyObject *self, PyObject *seq) summands */ if (Py_IS_FINITE(xsave)) { PyErr_SetString(PyExc_OverflowError, - "intermediate overflow in sum"); - goto _sum_error; + "intermediate overflow in fsum"); + goto _fsum_error; } if (Py_IS_INFINITY(xsave)) inf_sum += xsave; @@ -471,8 +471,8 @@ math_sum(PyObject *self, PyObject *seq) /* reset partials */ n = 0; } - else if (n >= m && _sum_realloc(&p, n, ps, &m)) - goto _sum_error; + else if (n >= m && _fsum_realloc(&p, n, ps, &m)) + goto _fsum_error; else p[n++] = x; } @@ -481,10 +481,10 @@ math_sum(PyObject *self, PyObject *seq) if (special_sum != 0.0) { if (Py_IS_NAN(inf_sum)) PyErr_SetString(PyExc_ValueError, - "-inf + inf in sum"); + "-inf + inf in fsum"); else sum = PyFloat_FromDouble(special_sum); - goto _sum_error; + goto _fsum_error; } hi = 0.0; @@ -518,7 +518,7 @@ math_sum(PyObject *self, PyObject *seq) } sum = PyFloat_FromDouble(hi); -_sum_error: +_fsum_error: PyFPE_END_PROTECT(hi) Py_DECREF(iter); if (p != ps) @@ -528,7 +528,7 @@ _sum_error: #undef NUM_PARTIALS -PyDoc_STRVAR(math_sum_doc, +PyDoc_STRVAR(math_fsum_doc, "sum(iterable)\n\n\ Return an accurate floating point sum of values in the iterable.\n\ Assumes IEEE-754 floating point arithmetic."); @@ -1021,6 +1021,7 @@ static PyMethodDef math_methods[] = { {"floor", math_floor, METH_O, math_floor_doc}, {"fmod", math_fmod, METH_VARARGS, math_fmod_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}, {"isinf", math_isinf, METH_O, math_isinf_doc}, {"isnan", math_isnan, METH_O, math_isnan_doc}, @@ -1034,10 +1035,9 @@ static PyMethodDef math_methods[] = { {"sin", math_sin, METH_O, math_sin_doc}, {"sinh", math_sinh, METH_O, math_sinh_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}, {"tanh", math_tanh, METH_O, math_tanh_doc}, - {"trunc", math_trunc, METH_O, math_trunc_doc}, + {"trunc", math_trunc, METH_O, math_trunc_doc}, {NULL, NULL} /* sentinel */ };