https://github.com/python/cpython/commit/169e7138ab84db465b6bf28e6c1dc6c39dbf89f4
commit: 169e7138ab84db465b6bf28e6c1dc6c39dbf89f4
branch: main
author: Sergey B Kirpichev <[email protected]>
committer: vstinner <[email protected]>
date: 2024-07-29T05:56:40+02:00
summary:

gh-122234: fix accuracy issues for sum() (#122236)

* Use compensated summation for complex sums with floating-point items.
  This amends #121176.

* sum() specializations for floats and complexes now use
  PyLong_AsDouble() instead of PyLong_AsLongAndOverflow() and
  compensated summation as well.

files:
A Misc/NEWS.d/next/Core and 
Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst
M Lib/test/test_builtin.py
M Python/bltinmodule.c

diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index c6a563cc90fec4..85f139db9bcd45 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -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):
@@ -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):
diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst b/Misc/NEWS.d/next/Core 
and Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst
new file mode 100644
index 00000000000000..b86d6fbdfc648f
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2024-07-24-17-11-51.gh-issue-122234.VxsP_F.rst 
@@ -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.
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 3f7bf4d568ee46..ae025e767ec838 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -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) {
@@ -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;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to