From 514d738d9eb21c611390fd415bf4e87f3a7a8696 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 22 May 2026 09:25:51 +0300 Subject: [PATCH 1/6] gh-85989: add HAVE_DOUBLE_ROUNDING check to test.support --- Lib/test/support/__init__.py | 6 ++++++ Lib/test/test_builtin.py | 7 +------ Lib/test/test_math.py | 7 +------ Lib/test/test_statistics.py | 8 +------- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 2cac70f4ab2afb..0348074ba6c8c6 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -73,6 +73,7 @@ "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield", "reset_code", "on_github_actions", "requires_root_user", "requires_non_root_user", + "HAVE_DOUBLE_ROUNDING", ] @@ -524,6 +525,11 @@ def dec(*args, **kwargs): float.__getformat__("double").startswith("IEEE"), "test requires IEEE 754 doubles") +# detect evidence of double-rounding: fsum is not always correctly +# rounded on machines that suffer from double rounding. +x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer +HAVE_DOUBLE_ROUNDING = (x + y == 1e16 + 4) + def requires_zlib(reason='requires zlib'): try: import zlib diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 1f52b16948c703..a3566eb38b3063 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -39,7 +39,7 @@ from test.support.script_helper import assert_python_ok from test.support.testcase import ComplexesAreIdenticalMixin from test.support.warnings_helper import check_warnings -from test.support import requires_IEEE_754 +from test.support import HAVE_DOUBLE_ROUNDING, requires_IEEE_754 from unittest.mock import MagicMock, patch try: import pty, signal @@ -47,11 +47,6 @@ pty = signal = None -# Detect evidence of double-rounding: sum() does not always -# get improved accuracy on machines that suffer from double rounding. -x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer -HAVE_DOUBLE_ROUNDING = (x + y == 1e16 + 4) - # used as proof of globals being used A_GLOBAL_VALUE = 123 A_SENTINEL = sentinel("A_SENTINEL") diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 8f9a239bead130..dd142aeb0cb888 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1,7 +1,7 @@ # Python test set -- math module # XXXX Should not do tests around zero only -from test.support import verbose, requires_IEEE_754 +from test.support import HAVE_DOUBLE_ROUNDING, verbose, requires_IEEE_754 from test import support import unittest import fractions @@ -23,11 +23,6 @@ FLOAT_MAX = sys.float_info.max FLOAT_MIN = sys.float_info.min -# detect evidence of double-rounding: fsum is not always correctly -# rounded on machines that suffer from double rounding. -x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer -HAVE_DOUBLE_ROUNDING = (x + y == 1e16 + 4) - # locate file with test values if __name__ == '__main__': file = sys.argv[0] diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 677a87b51b9192..18ac5b17b9b481 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -16,7 +16,7 @@ import sys import unittest from test import support -from test.support import import_helper, requires_IEEE_754 +from test.support import HAVE_DOUBLE_ROUNDING, import_helper, requires_IEEE_754 from decimal import Decimal from fractions import Fraction @@ -28,12 +28,6 @@ # === Helper functions and class === -# Test copied from Lib/test/test_math.py -# detect evidence of double-rounding: fsum is not always correctly -# rounded on machines that suffer from double rounding. -x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer -HAVE_DOUBLE_ROUNDING = (x + y == 1e16 + 4) - def sign(x): """Return -1.0 for negatives, including -0.0, otherwise +1.0.""" return math.copysign(1, x) From 6ca94a6b03bc56d2912a8cc20d1f4cffcf5ee7a3 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 26 May 2026 05:09:32 +0300 Subject: [PATCH 2/6] add instead the skip_if_have_double_rounding decorator --- Lib/test/support/__init__.py | 11 +++++++---- Lib/test/test_builtin.py | 5 ++--- Lib/test/test_math.py | 15 ++++++--------- Lib/test/test_statistics.py | 6 +++--- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 5414aa98519d6b..d12ec6244169b0 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -73,7 +73,7 @@ "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield", "reset_code", "on_github_actions", "requires_root_user", "requires_non_root_user", - "HAVE_DOUBLE_ROUNDING", + "skip_if_have_double_rounding", ] @@ -525,10 +525,13 @@ def dec(*args, **kwargs): float.__getformat__("double").startswith("IEEE"), "test requires IEEE 754 doubles") -# detect evidence of double-rounding: fsum is not always correctly -# rounded on machines that suffer from double rounding. +# detect evidence of double-rounding: x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer -HAVE_DOUBLE_ROUNDING = (x + y == 1e16 + 4) +skip_if_have_double_rounding = unittest.skipIf(x + y == 1e16 + 4, + ("accuracy not guaranteed on " + "machines with double " + "rounding")) + def requires_zlib(reason='requires zlib'): try: diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index a3566eb38b3063..cb2e96a8f6b11b 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -39,7 +39,7 @@ from test.support.script_helper import assert_python_ok from test.support.testcase import ComplexesAreIdenticalMixin from test.support.warnings_helper import check_warnings -from test.support import HAVE_DOUBLE_ROUNDING, requires_IEEE_754 +from test.support import requires_IEEE_754, skip_if_have_double_rounding from unittest.mock import MagicMock, patch try: import pty, signal @@ -2230,8 +2230,7 @@ def __getitem__(self, index): complex(2, -0.0)) @requires_IEEE_754 - @unittest.skipIf(HAVE_DOUBLE_ROUNDING, - "sum accuracy not guaranteed on machines with double rounding") + @skip_if_have_double_rounding @support.cpython_only # Other implementations may choose a different algorithm def test_sum_accuracy(self): self.assertEqual(sum([0.1] * 10), 1.0) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index dd142aeb0cb888..16f28af5243294 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1,7 +1,8 @@ # Python test set -- math module # XXXX Should not do tests around zero only -from test.support import HAVE_DOUBLE_ROUNDING, verbose, requires_IEEE_754 +from test.support import (verbose, requires_IEEE_754, + skip_if_have_double_rounding) from test import support import unittest import fractions @@ -678,8 +679,7 @@ def testfrexp(name, result, expected): self.assertTrue(math.isnan(math.frexp(NAN)[0])) @requires_IEEE_754 - @unittest.skipIf(HAVE_DOUBLE_ROUNDING, - "fsum is not exact on machines with double rounding") + @skip_if_have_double_rounding def testFsum(self): # math.fsum relies on exact rounding for correct operation. # There's a known problem with IA32 floating-point that causes @@ -915,8 +915,7 @@ def testHypot(self): self.assertRaises(TypeError, math.hypot, *([1.0]*18), 'spam') @requires_IEEE_754 - @unittest.skipIf(HAVE_DOUBLE_ROUNDING, - "hypot() loses accuracy on machines with double rounding") + @skip_if_have_double_rounding def testHypotAccuracy(self): # Verify improved accuracy in cases that were known to be inaccurate. # @@ -1405,8 +1404,7 @@ def __rmul__(self, other): self.assertEqual(sumprod(*args), 0.0) @requires_IEEE_754 - @unittest.skipIf(HAVE_DOUBLE_ROUNDING, - "sumprod() accuracy not guaranteed on machines with double rounding") + @skip_if_have_double_rounding @support.cpython_only # Other implementations may choose a different algorithm def test_sumprod_accuracy(self): sumprod = math.sumprod @@ -1491,8 +1489,7 @@ def run(func, *args): ) @requires_IEEE_754 - @unittest.skipIf(HAVE_DOUBLE_ROUNDING, - "sumprod() accuracy not guaranteed on machines with double rounding") + @skip_if_have_double_rounding @support.cpython_only # Other implementations may choose a different algorithm @support.requires_resource('cpu') def test_sumprod_extended_precision_accuracy(self): diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 18ac5b17b9b481..09549849bbb008 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -16,7 +16,8 @@ import sys import unittest from test import support -from test.support import HAVE_DOUBLE_ROUNDING, import_helper, requires_IEEE_754 +from test.support import (import_helper, requires_IEEE_754, + skip_if_have_double_rounding) from decimal import Decimal from fractions import Fraction @@ -2790,8 +2791,7 @@ def test_sqrtprod_helper_function_fundamentals(self): self.assertEqual(sign(actual), sign(expected)) @requires_IEEE_754 - @unittest.skipIf(HAVE_DOUBLE_ROUNDING, - "accuracy not guaranteed on machines with double rounding") + @skip_if_have_double_rounding @support.cpython_only # Allow for a weaker sumprod() implementation def test_sqrtprod_helper_function_improved_accuracy(self): # Test a known example where accuracy is improved From dd5edc3df79c5c4e7ea1bbf2dd39a8dbc772f193 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 26 May 2026 05:35:41 +0300 Subject: [PATCH 3/6] address review: rename decorator --- Lib/test/support/__init__.py | 9 ++++----- Lib/test/test_builtin.py | 4 ++-- Lib/test/test_math.py | 10 +++++----- Lib/test/test_statistics.py | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index d12ec6244169b0..badbcef56b0802 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -73,7 +73,7 @@ "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield", "reset_code", "on_github_actions", "requires_root_user", "requires_non_root_user", - "skip_if_have_double_rounding", + "skip_if_double_rounding", ] @@ -527,10 +527,9 @@ def dec(*args, **kwargs): # detect evidence of double-rounding: x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer -skip_if_have_double_rounding = unittest.skipIf(x + y == 1e16 + 4, - ("accuracy not guaranteed on " - "machines with double " - "rounding")) +skip_if_double_rounding = unittest.skipIf(x + y == 1e16 + 4, + ("accuracy not guaranteed on " + "machines with double rounding")) def requires_zlib(reason='requires zlib'): diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index cb2e96a8f6b11b..1d2c105ac047e1 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -39,7 +39,7 @@ from test.support.script_helper import assert_python_ok from test.support.testcase import ComplexesAreIdenticalMixin from test.support.warnings_helper import check_warnings -from test.support import requires_IEEE_754, skip_if_have_double_rounding +from test.support import requires_IEEE_754, skip_if_double_rounding from unittest.mock import MagicMock, patch try: import pty, signal @@ -2230,7 +2230,7 @@ def __getitem__(self, index): complex(2, -0.0)) @requires_IEEE_754 - @skip_if_have_double_rounding + @skip_if_double_rounding @support.cpython_only # Other implementations may choose a different algorithm def test_sum_accuracy(self): self.assertEqual(sum([0.1] * 10), 1.0) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 16f28af5243294..4cc0f340ad6a86 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -2,7 +2,7 @@ # XXXX Should not do tests around zero only from test.support import (verbose, requires_IEEE_754, - skip_if_have_double_rounding) + skip_if_double_rounding) from test import support import unittest import fractions @@ -679,7 +679,7 @@ def testfrexp(name, result, expected): self.assertTrue(math.isnan(math.frexp(NAN)[0])) @requires_IEEE_754 - @skip_if_have_double_rounding + @skip_if_double_rounding def testFsum(self): # math.fsum relies on exact rounding for correct operation. # There's a known problem with IA32 floating-point that causes @@ -915,7 +915,7 @@ def testHypot(self): self.assertRaises(TypeError, math.hypot, *([1.0]*18), 'spam') @requires_IEEE_754 - @skip_if_have_double_rounding + @skip_if_double_rounding def testHypotAccuracy(self): # Verify improved accuracy in cases that were known to be inaccurate. # @@ -1404,7 +1404,7 @@ def __rmul__(self, other): self.assertEqual(sumprod(*args), 0.0) @requires_IEEE_754 - @skip_if_have_double_rounding + @skip_if_double_rounding @support.cpython_only # Other implementations may choose a different algorithm def test_sumprod_accuracy(self): sumprod = math.sumprod @@ -1489,7 +1489,7 @@ def run(func, *args): ) @requires_IEEE_754 - @skip_if_have_double_rounding + @skip_if_double_rounding @support.cpython_only # Other implementations may choose a different algorithm @support.requires_resource('cpu') def test_sumprod_extended_precision_accuracy(self): diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 09549849bbb008..87630e850b2dbd 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -17,7 +17,7 @@ import unittest from test import support from test.support import (import_helper, requires_IEEE_754, - skip_if_have_double_rounding) + skip_if_double_rounding) from decimal import Decimal from fractions import Fraction @@ -2791,7 +2791,7 @@ def test_sqrtprod_helper_function_fundamentals(self): self.assertEqual(sign(actual), sign(expected)) @requires_IEEE_754 - @skip_if_have_double_rounding + @skip_if_double_rounding @support.cpython_only # Allow for a weaker sumprod() implementation def test_sqrtprod_helper_function_improved_accuracy(self): # Test a known example where accuracy is improved From afa0b672d45b3ef4b12590385b3f493fe059795d Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 26 May 2026 05:46:05 +0300 Subject: [PATCH 4/6] Update Lib/test/support/__init__.py Co-authored-by: Victor Stinner --- Lib/test/support/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 3a790d33f7ad7f..b1099930e0fa51 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -528,8 +528,8 @@ def dec(*args, **kwargs): # detect evidence of double-rounding: x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer skip_if_double_rounding = unittest.skipIf(x + y == 1e16 + 4, - ("accuracy not guaranteed on " - "machines with double rounding")) + "accuracy not guaranteed on " + "machines with double rounding") def requires_zlib(reason='requires zlib'): From 97ee9ebd59ae4ac6f94516a083ac9e571bf820f8 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 26 May 2026 05:56:59 +0300 Subject: [PATCH 5/6] +1 --- Lib/test/support/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index b1099930e0fa51..288d9a5a907e7d 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -527,7 +527,8 @@ def dec(*args, **kwargs): # detect evidence of double-rounding: x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer -skip_if_double_rounding = unittest.skipIf(x + y == 1e16 + 4, +HAVE_DOUBLE_ROUNDING = (x + y == 1e16 + 4) +skip_if_double_rounding = unittest.skipIf(HAVE_DOUBLE_ROUNDING, "accuracy not guaranteed on " "machines with double rounding") From 6a75c91c9c887d77285b073589920bad5426572c Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Thu, 28 May 2026 04:46:21 +0300 Subject: [PATCH 6/6] address review: delete x, y, HAVE_DOUBLE_ROUNDING --- Lib/test/support/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 7ac6540b59842d..5b0ae098b636ed 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -521,6 +521,7 @@ def dec(*args, **kwargs): skip_if_double_rounding = unittest.skipIf(HAVE_DOUBLE_ROUNDING, "accuracy not guaranteed on " "machines with double rounding") +del x, y, HAVE_DOUBLE_ROUNDING def requires_zlib(reason='requires zlib'):