mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
bc93923a2d
commit
169e7138ab
|
@ -1778,6 +1778,8 @@ class BuiltinTest(unittest.TestCase):
|
|||
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 @@ class BuiltinTest(unittest.TestCase):
|
|||
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):
|
||||
|
|
|
@ -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.
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue