diff options
author | Raymond Hettinger <rhettinger@users.noreply.github.com> | 2022-12-23 22:35:58 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-23 22:35:58 (GMT) |
commit | 5d84966cce6c596da22922a07f49bde959ff5201 (patch) | |
tree | e44414a0ff5f02233158709844e0932b08f54c63 /Python | |
parent | 1ecfd1ebf1f53ef6ac82085b25ed09952b470d4e (diff) | |
download | cpython-5d84966cce6c596da22922a07f49bde959ff5201.zip cpython-5d84966cce6c596da22922a07f49bde959ff5201.tar.gz cpython-5d84966cce6c596da22922a07f49bde959ff5201.tar.bz2 |
GH-100425: Improve accuracy of builtin sum() for float inputs (GH-100426)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bltinmodule.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index ff96c25..2d4822e 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2532,6 +2532,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) if (PyFloat_CheckExact(result)) { double f_result = PyFloat_AS_DOUBLE(result); + double c = 0.0; Py_SETREF(result, NULL); while(result == NULL) { item = PyIter_Next(iter); @@ -2539,10 +2540,25 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) Py_DECREF(iter); if (PyErr_Occurred()) return NULL; + /* Avoid losing the sign on a negative result, + and don't let adding the compensation convert + an infinite or overflowed sum to a NaN. */ + if (c && Py_IS_FINITE(c)) { + f_result += c; + } return PyFloat_FromDouble(f_result); } if (PyFloat_CheckExact(item)) { - f_result += PyFloat_AS_DOUBLE(item); + // Improved Kahan–Babuška algorithm by Arnold Neumaier + // https://www.mat.univie.ac.at/~neum/scan/01.pdf + double x = PyFloat_AS_DOUBLE(item); + double t = f_result + x; + if (fabs(f_result) >= fabs(x)) { + c += (f_result - t) + x; + } else { + c += (x - t) + f_result; + } + f_result = t; _Py_DECREF_SPECIALIZED(item, _PyFloat_ExactDealloc); continue; } @@ -2556,6 +2572,9 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) continue; } } + if (c && Py_IS_FINITE(c)) { + f_result += c; + } result = PyFloat_FromDouble(f_result); if (result == NULL) { Py_DECREF(item); |