Skip to content

Commit

Permalink
pythongh-122234: fix accuracy issues for sum() (python#122236)
Browse files Browse the repository at this point in the history
* Use compensated summation for complex sums with floating-point items.
  This amends python#121176.

* sum() specializations for floats and complexes now use
  PyLong_AsDouble() instead of PyLong_AsLongAndOverflow() and
  compensated summation as well.
  • Loading branch information
skirpichev authored Jul 29, 2024
1 parent bc93923 commit 169e713
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 11 deletions.
5 changes: 5 additions & 0 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,8 @@ def test_sum(self):
self.assertRaises(TypeError, sum, [], '')
self.assertRaises(TypeError, sum, [], b'')
self.assertRaises(TypeError, sum, [], bytearray())
self.assertRaises(OverflowError, sum, [1.0, 10**1000])
self.assertRaises(OverflowError, sum, [1j, 10**1000])

class BadSeq:
def __getitem__(self, index):
Expand All @@ -1803,6 +1805,9 @@ def test_sum_accuracy(self):
self.assertEqual(sum([1.0, 10E100, 1.0, -10E100, 2j]), 2+2j)
self.assertEqual(sum([2+1j, 10E100j, 1j, -10E100j]), 2+2j)
self.assertEqual(sum([1j, 1, 10E100j, 1j, 1.0, -10E100j]), 2+2j)
self.assertEqual(sum([2j, 1., 10E100, 1., -10E100]), 2+2j)
self.assertEqual(sum([1.0, 10**100, 1.0, -10**100]), 2.0)
self.assertEqual(sum([2j, 1.0, 10**100, 1.0, -10**100]), 2+2j)
self.assertEqual(sum([0.1j]*10 + [fractions.Fraction(1, 10)]), 0.1+1j)

def test_type(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Specializations for sums with float and complex inputs in :func:`sum()` now
always use compensated summation. Also, for integer items in above
specializations: :c:func:`PyLong_AsDouble` is used, instead of
:c:func:`PyLong_AsLongAndOverflow`. Patch by Sergey B Kirpichev.
24 changes: 13 additions & 11 deletions Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2687,14 +2687,15 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
continue;
}
if (PyLong_Check(item)) {
long value;
int overflow;
value = PyLong_AsLongAndOverflow(item, &overflow);
if (!overflow) {
re_sum.hi += (double)value;
double value = PyLong_AsDouble(item);
if (value != -1.0 || !PyErr_Occurred()) {
re_sum = cs_add(re_sum, value);
Py_DECREF(item);
continue;
}
else {
return NULL;
}
}
result = PyFloat_FromDouble(cs_to_double(re_sum));
if (result == NULL) {
Expand Down Expand Up @@ -2736,19 +2737,20 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
continue;
}
if (PyLong_Check(item)) {
long value;
int overflow;
value = PyLong_AsLongAndOverflow(item, &overflow);
if (!overflow) {
re_sum.hi += (double)value;
double value = PyLong_AsDouble(item);
if (value != -1.0 || !PyErr_Occurred()) {
re_sum = cs_add(re_sum, value);
im_sum.hi += 0.0;
Py_DECREF(item);
continue;
}
else {
return NULL;
}
}
if (PyFloat_Check(item)) {
double value = PyFloat_AS_DOUBLE(item);
re_sum.hi += value;
re_sum = cs_add(re_sum, value);
im_sum.hi += 0.0;
_Py_DECREF_SPECIALIZED(item, _PyFloat_ExactDealloc);
continue;
Expand Down

0 comments on commit 169e713

Please sign in to comment.