From 4a7668adca60a75fb41c87781caa5672871f65cf Mon Sep 17 00:00:00 2001 From: Nick Coghlan Date: Sat, 8 Feb 2014 23:55:14 +1000 Subject: [PATCH] Close #20536: correctly handle Decimal exponents in statistics --- Lib/statistics.py | 6 +++++- Lib/test/test_statistics.py | 38 +++++++++++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Lib/statistics.py b/Lib/statistics.py index e1dfbd4931..25a26d4aa7 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -243,9 +243,13 @@ def _decimal_to_ratio(d): num = 0 for digit in digits: num = num*10 + digit + if exp < 0: + den = 10**-exp + else: + num *= 10**exp + den = 1 if sign: num = -num - den = 10**-exp return (num, den) diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 49b8597a91..6f5c9a649d 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -686,6 +686,38 @@ class DecimalToRatioTest(unittest.TestCase): for d in (Decimal('NAN'), Decimal('sNAN'), Decimal('INF')): self.assertRaises(ValueError, statistics._decimal_to_ratio, d) + def test_sign(self): + # Test sign is calculated correctly. + numbers = [Decimal("9.8765e12"), Decimal("9.8765e-12")] + for d in numbers: + # First test positive decimals. + assert d > 0 + num, den = statistics._decimal_to_ratio(d) + self.assertGreaterEqual(num, 0) + self.assertGreater(den, 0) + # Then test negative decimals. + num, den = statistics._decimal_to_ratio(-d) + self.assertLessEqual(num, 0) + self.assertGreater(den, 0) + + def test_negative_exponent(self): + # Test result when the exponent is negative. + t = statistics._decimal_to_ratio(Decimal("0.1234")) + self.assertEqual(t, (1234, 10000)) + + def test_positive_exponent(self): + # Test results when the exponent is positive. + t = statistics._decimal_to_ratio(Decimal("1.234e7")) + self.assertEqual(t, (12340000, 1)) + + def test_regression_20536(self): + # Regression test for issue 20536. + # See http://bugs.python.org/issue20536 + t = statistics._decimal_to_ratio(Decimal("1e2")) + self.assertEqual(t, (100, 1)) + t = statistics._decimal_to_ratio(Decimal("1.47e5")) + self.assertEqual(t, (147000, 1)) + class CheckTypeTest(unittest.TestCase): # Test _check_type private function. @@ -1074,6 +1106,12 @@ class TestMean(NumericTestCase, AverageMixin, UnivariateTypeMixin): actual = self.func(data*2) self.assertApproxEqual(actual, expected) + def test_regression_20561(self): + # Regression test for issue 20561. + # See http://bugs.python.org/issue20561 + d = Decimal('1e4') + self.assertEqual(statistics.mean([d]), d) + class TestMedian(NumericTestCase, AverageMixin): # Common tests for median and all median.* functions. diff --git a/Misc/NEWS b/Misc/NEWS index 10ebee27b3..028f4d2224 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -27,6 +27,9 @@ Core and Builtins Library ------- +- Issue #20536: the statistics module now correctly handle Decimal instances + with positive exponents + - Issue #18805: the netmask/hostmask parsing in ipaddress now more reliably filters out illegal values and correctly allows any valid prefix length. -- 2.40.0