]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-139074: Fix missing high precision case in sumprod() (gh-139075)
authorRaymond Hettinger <rhettinger@users.noreply.github.com>
Wed, 17 Sep 2025 21:50:15 +0000 (16:50 -0500)
committerGitHub <noreply@github.com>
Wed, 17 Sep 2025 21:50:15 +0000 (16:50 -0500)
Lib/test/test_math.py
Misc/NEWS.d/next/Core_and_Builtins/2025-09-17-13-21-26.gh-issue-139074.dVZO5F.rst [new file with mode: 0644]
Modules/mathmodule.c

index e3b0d4fa9eeeb336848ed85d7e9c3c7504ef942e..92326a46c33963818efc6d5652cba3ea395204ef 100644 (file)
@@ -1485,7 +1485,9 @@ class MathTests(unittest.TestCase):
 
         # Error cases that arose during development
         args = ((-5, -5, 10), (1.5, 4611686018427387904, 2305843009213693952))
-        self.assertEqual(sumprod(*args), 0.0)
+        self.assertEqual(sumprod(*args), -7.5)
+        self.assertEqual(sumprod([-0.01, 1, -1, 0.01], [1, 1, 1, 1]), 0.0)
+        self.assertEqual(sumprod([1, 1, 1, 1], [-0.01, 1, -1, 0.01], ), 0.0)
 
     @requires_IEEE_754
     @unittest.skipIf(HAVE_DOUBLE_ROUNDING,
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-17-13-21-26.gh-issue-139074.dVZO5F.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-17-13-21-26.gh-issue-139074.dVZO5F.rst
new file mode 100644 (file)
index 0000000..56c9f21
--- /dev/null
@@ -0,0 +1,2 @@
+Fixed a missing case in :func:`math.sumprod` where a low precision path was
+taken when an int/int input pair followed a float input.
index c631beb9ce5477fafc5bc242b19456f3658a7042..d8bf9e76cdd0827e09756b6992fcdb155c911318 100644 (file)
@@ -2937,32 +2937,31 @@ math_sumprod_impl(PyObject *module, PyObject *p, PyObject *q)
 
             if (!finished) {
                 double flt_p, flt_q;
-                bool p_type_float = PyFloat_CheckExact(p_i);
-                bool q_type_float = PyFloat_CheckExact(q_i);
-                if (p_type_float && q_type_float) {
-                    flt_p = PyFloat_AS_DOUBLE(p_i);
-                    flt_q = PyFloat_AS_DOUBLE(q_i);
-                } else if (p_type_float && (PyLong_CheckExact(q_i) || PyBool_Check(q_i))) {
-                    /* We care about float/int pairs and int/float pairs because
-                       they arise naturally in several use cases such as price
-                       times quantity, measurements with integer weights, or
-                       data selected by a vector of bools. */
+
+                if (PyFloat_CheckExact(p_i)) {
                     flt_p = PyFloat_AS_DOUBLE(p_i);
-                    flt_q = PyLong_AsDouble(q_i);
-                    if (flt_q == -1.0 && PyErr_Occurred()) {
+                } else if (PyLong_CheckExact(p_i) || PyBool_Check(p_i)) {
+                    flt_p = PyLong_AsDouble(p_i);
+                    if (flt_p == -1.0 && PyErr_Occurred()) {
                         PyErr_Clear();
                         goto finalize_flt_path;
                     }
-                } else if (q_type_float && (PyLong_CheckExact(p_i) || PyBool_Check(p_i))) {
+                } else {
+                    goto finalize_flt_path;
+                }
+
+                if (PyFloat_CheckExact(q_i)) {
                     flt_q = PyFloat_AS_DOUBLE(q_i);
-                    flt_p = PyLong_AsDouble(p_i);
-                    if (flt_p == -1.0 && PyErr_Occurred()) {
+                } else if (PyLong_CheckExact(q_i) || PyBool_Check(q_i)) {
+                    flt_q = PyLong_AsDouble(q_i);
+                    if (flt_q == -1.0 && PyErr_Occurred()) {
                         PyErr_Clear();
                         goto finalize_flt_path;
                     }
                 } else {
                     goto finalize_flt_path;
                 }
+
                 TripleLength new_flt_total = tl_fma(flt_p, flt_q, flt_total);
                 if (isfinite(new_flt_total.hi)) {
                     flt_total = new_flt_total;