|
|
|
@ -1010,273 +1010,6 @@ class FailNegTest(unittest.TestCase): |
|
|
|
self.assertEqual(errmsg, msg) |
|
|
|
|
|
|
|
|
|
|
|
class Test_Product(NumericTestCase): |
|
|
|
"""Test the private _product function.""" |
|
|
|
|
|
|
|
def test_ints(self): |
|
|
|
data = [1, 2, 5, 7, 9] |
|
|
|
self.assertEqual(statistics._product(data), (0, 630)) |
|
|
|
self.assertEqual(statistics._product(data*100), (0, 630**100)) |
|
|
|
|
|
|
|
def test_floats(self): |
|
|
|
data = [1.0, 2.0, 4.0, 8.0] |
|
|
|
self.assertEqual(statistics._product(data), (8, 0.25)) |
|
|
|
|
|
|
|
def test_overflow(self): |
|
|
|
# Test with floats that overflow. |
|
|
|
data = [1e300]*5 |
|
|
|
self.assertEqual(statistics._product(data), (5980, 0.6928287951283193)) |
|
|
|
|
|
|
|
def test_fractions(self): |
|
|
|
F = Fraction |
|
|
|
data = [F(14, 23), F(69, 1), F(665, 529), F(299, 105), F(1683, 39)] |
|
|
|
exp, mant = statistics._product(data) |
|
|
|
self.assertEqual(exp, 0) |
|
|
|
self.assertEqual(mant, F(2*3*7*11*17*19, 23)) |
|
|
|
self.assertTrue(isinstance(mant, F)) |
|
|
|
# Mixed Fraction and int. |
|
|
|
data = [3, 25, F(2, 15)] |
|
|
|
exp, mant = statistics._product(data) |
|
|
|
self.assertEqual(exp, 0) |
|
|
|
self.assertEqual(mant, F(10)) |
|
|
|
self.assertTrue(isinstance(mant, F)) |
|
|
|
|
|
|
|
def test_decimal(self): |
|
|
|
D = Decimal |
|
|
|
data = [D('24.5'), D('17.6'), D('0.025'), D('1.3')] |
|
|
|
expected = D('14.014000') |
|
|
|
self.assertEqual(statistics._product(data), (0, expected)) |
|
|
|
|
|
|
|
def test_mixed_decimal_float(self): |
|
|
|
# Test that mixed Decimal and float raises. |
|
|
|
self.assertRaises(TypeError, statistics._product, [1.0, Decimal(1)]) |
|
|
|
self.assertRaises(TypeError, statistics._product, [Decimal(1), 1.0]) |
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(True, "FIXME: tests known to fail, see issue #27181") |
|
|
|
class Test_Nth_Root(NumericTestCase): |
|
|
|
"""Test the functionality of the private _nth_root function.""" |
|
|
|
|
|
|
|
def setUp(self): |
|
|
|
self.nroot = statistics._nth_root |
|
|
|
|
|
|
|
# --- Special values (infinities, NANs, zeroes) --- |
|
|
|
|
|
|
|
def test_float_NAN(self): |
|
|
|
# Test that the root of a float NAN is a float NAN. |
|
|
|
NAN = float('nan') |
|
|
|
for n in range(2, 9): |
|
|
|
with self.subTest(n=n): |
|
|
|
result = self.nroot(NAN, n) |
|
|
|
self.assertTrue(math.isnan(result)) |
|
|
|
|
|
|
|
def test_decimal_QNAN(self): |
|
|
|
# Test the behaviour when taking the root of a Decimal quiet NAN. |
|
|
|
NAN = decimal.Decimal('nan') |
|
|
|
with decimal.localcontext() as ctx: |
|
|
|
ctx.traps[decimal.InvalidOperation] = 1 |
|
|
|
self.assertRaises(decimal.InvalidOperation, self.nroot, NAN, 5) |
|
|
|
ctx.traps[decimal.InvalidOperation] = 0 |
|
|
|
self.assertTrue(self.nroot(NAN, 5).is_qnan()) |
|
|
|
|
|
|
|
def test_decimal_SNAN(self): |
|
|
|
# Test that taking the root of a Decimal sNAN always raises. |
|
|
|
sNAN = decimal.Decimal('snan') |
|
|
|
with decimal.localcontext() as ctx: |
|
|
|
ctx.traps[decimal.InvalidOperation] = 1 |
|
|
|
self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) |
|
|
|
ctx.traps[decimal.InvalidOperation] = 0 |
|
|
|
self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5) |
|
|
|
|
|
|
|
def test_inf(self): |
|
|
|
# Test that the root of infinity is infinity. |
|
|
|
for INF in (float('inf'), decimal.Decimal('inf')): |
|
|
|
for n in range(2, 9): |
|
|
|
with self.subTest(n=n, inf=INF): |
|
|
|
self.assertEqual(self.nroot(INF, n), INF) |
|
|
|
|
|
|
|
# FIXME: need to check Decimal zeroes too. |
|
|
|
def test_zero(self): |
|
|
|
# Test that the root of +0.0 is +0.0. |
|
|
|
for n in range(2, 11): |
|
|
|
with self.subTest(n=n): |
|
|
|
result = self.nroot(+0.0, n) |
|
|
|
self.assertEqual(result, 0.0) |
|
|
|
self.assertEqual(sign(result), +1) |
|
|
|
|
|
|
|
# FIXME: need to check Decimal zeroes too. |
|
|
|
def test_neg_zero(self): |
|
|
|
# Test that the root of -0.0 is -0.0. |
|
|
|
for n in range(2, 11): |
|
|
|
with self.subTest(n=n): |
|
|
|
result = self.nroot(-0.0, n) |
|
|
|
self.assertEqual(result, 0.0) |
|
|
|
self.assertEqual(sign(result), -1) |
|
|
|
|
|
|
|
# --- Test return types --- |
|
|
|
|
|
|
|
def check_result_type(self, x, n, outtype): |
|
|
|
self.assertIsInstance(self.nroot(x, n), outtype) |
|
|
|
class MySubclass(type(x)): |
|
|
|
pass |
|
|
|
self.assertIsInstance(self.nroot(MySubclass(x), n), outtype) |
|
|
|
|
|
|
|
def testDecimal(self): |
|
|
|
# Test that Decimal arguments return Decimal results. |
|
|
|
self.check_result_type(decimal.Decimal('33.3'), 3, decimal.Decimal) |
|
|
|
|
|
|
|
def testFloat(self): |
|
|
|
# Test that other arguments return float results. |
|
|
|
for x in (0.2, Fraction(11, 7), 91): |
|
|
|
self.check_result_type(x, 6, float) |
|
|
|
|
|
|
|
# --- Test bad input --- |
|
|
|
|
|
|
|
def testBadOrderTypes(self): |
|
|
|
# Test that nroot raises correctly when n has the wrong type. |
|
|
|
for n in (5.0, 2j, None, 'x', b'x', [], {}, set(), sign): |
|
|
|
with self.subTest(n=n): |
|
|
|
self.assertRaises(TypeError, self.nroot, 2.5, n) |
|
|
|
|
|
|
|
def testBadOrderValues(self): |
|
|
|
# Test that nroot raises correctly when n has a wrong value. |
|
|
|
for n in (1, 0, -1, -2, -87): |
|
|
|
with self.subTest(n=n): |
|
|
|
self.assertRaises(ValueError, self.nroot, 2.5, n) |
|
|
|
|
|
|
|
def testBadTypes(self): |
|
|
|
# Test that nroot raises correctly when x has the wrong type. |
|
|
|
for x in (None, 'x', b'x', [], {}, set(), sign): |
|
|
|
with self.subTest(x=x): |
|
|
|
self.assertRaises(TypeError, self.nroot, x, 3) |
|
|
|
|
|
|
|
def testNegativeError(self): |
|
|
|
# Test negative x raises correctly. |
|
|
|
x = random.uniform(-20.0, -0.1) |
|
|
|
assert x < 0 |
|
|
|
for n in range(3, 7): |
|
|
|
with self.subTest(x=x, n=n): |
|
|
|
self.assertRaises(ValueError, self.nroot, x, n) |
|
|
|
# And Decimal. |
|
|
|
self.assertRaises(ValueError, self.nroot, Decimal(-27), 3) |
|
|
|
|
|
|
|
# --- Test that nroot is never worse than calling math.pow() --- |
|
|
|
|
|
|
|
def check_error_is_no_worse(self, x, n): |
|
|
|
y = math.pow(x, n) |
|
|
|
with self.subTest(x=x, n=n, y=y): |
|
|
|
err1 = abs(self.nroot(y, n) - x) |
|
|
|
err2 = abs(math.pow(y, 1.0/n) - x) |
|
|
|
self.assertLessEqual(err1, err2) |
|
|
|
|
|
|
|
def testCompareWithPowSmall(self): |
|
|
|
# Compare nroot with pow for small values of x. |
|
|
|
for i in range(200): |
|
|
|
x = random.uniform(1e-9, 1.0-1e-9) |
|
|
|
n = random.choice(range(2, 16)) |
|
|
|
self.check_error_is_no_worse(x, n) |
|
|
|
|
|
|
|
def testCompareWithPowMedium(self): |
|
|
|
# Compare nroot with pow for medium-sized values of x. |
|
|
|
for i in range(200): |
|
|
|
x = random.uniform(1.0, 100.0) |
|
|
|
n = random.choice(range(2, 16)) |
|
|
|
self.check_error_is_no_worse(x, n) |
|
|
|
|
|
|
|
def testCompareWithPowLarge(self): |
|
|
|
# Compare nroot with pow for largish values of x. |
|
|
|
for i in range(200): |
|
|
|
x = random.uniform(100.0, 10000.0) |
|
|
|
n = random.choice(range(2, 16)) |
|
|
|
self.check_error_is_no_worse(x, n) |
|
|
|
|
|
|
|
def testCompareWithPowHuge(self): |
|
|
|
# Compare nroot with pow for huge values of x. |
|
|
|
for i in range(200): |
|
|
|
x = random.uniform(1e20, 1e50) |
|
|
|
# We restrict the order here to avoid an Overflow error. |
|
|
|
n = random.choice(range(2, 7)) |
|
|
|
self.check_error_is_no_worse(x, n) |
|
|
|
|
|
|
|
# --- Test for numerically correct answers --- |
|
|
|
|
|
|
|
def testExactPowers(self): |
|
|
|
# Test that small integer powers are calculated exactly. |
|
|
|
for i in range(1, 51): |
|
|
|
for n in range(2, 16): |
|
|
|
if (i, n) == (35, 13): |
|
|
|
# See testExpectedFailure35p13 |
|
|
|
continue |
|
|
|
with self.subTest(i=i, n=n): |
|
|
|
x = i**n |
|
|
|
self.assertEqual(self.nroot(x, n), i) |
|
|
|
|
|
|
|
def testExpectedFailure35p13(self): |
|
|
|
# Test the expected failure 35**13 is almost exact. |
|
|
|
x = 35**13 |
|
|
|
err = abs(self.nroot(x, 13) - 35) |
|
|
|
self.assertLessEqual(err, 0.000000001) |
|
|
|
|
|
|
|
def testOne(self): |
|
|
|
# Test that the root of 1.0 is 1.0. |
|
|
|
for n in range(2, 11): |
|
|
|
with self.subTest(n=n): |
|
|
|
self.assertEqual(self.nroot(1.0, n), 1.0) |
|
|
|
|
|
|
|
def testFraction(self): |
|
|
|
# Test Fraction results. |
|
|
|
x = Fraction(89, 75) |
|
|
|
self.assertEqual(self.nroot(x**12, 12), float(x)) |
|
|
|
|
|
|
|
def testInt(self): |
|
|
|
# Test int results. |
|
|
|
x = 276 |
|
|
|
self.assertEqual(self.nroot(x**24, 24), x) |
|
|
|
|
|
|
|
def testBigInt(self): |
|
|
|
# Test that ints too big to convert to floats work. |
|
|
|
bignum = 10**20 # That's not that big... |
|
|
|
self.assertEqual(self.nroot(bignum**280, 280), bignum) |
|
|
|
# Can we make it bigger? |
|
|
|
hugenum = bignum**50 |
|
|
|
# Make sure that it is too big to convert to a float. |
|
|
|
try: |
|
|
|
y = float(hugenum) |
|
|
|
except OverflowError: |
|
|
|
pass |
|
|
|
else: |
|
|
|
raise AssertionError('hugenum is not big enough') |
|
|
|
self.assertEqual(self.nroot(hugenum, 50), float(bignum)) |
|
|
|
|
|
|
|
def testDecimal(self): |
|
|
|
# Test Decimal results. |
|
|
|
for s in '3.759 64.027 5234.338'.split(): |
|
|
|
x = decimal.Decimal(s) |
|
|
|
with self.subTest(x=x): |
|
|
|
a = self.nroot(x**5, 5) |
|
|
|
self.assertEqual(a, x) |
|
|
|
a = self.nroot(x**17, 17) |
|
|
|
self.assertEqual(a, x) |
|
|
|
|
|
|
|
def testFloat(self): |
|
|
|
# Test float results. |
|
|
|
for x in (3.04e-16, 18.25, 461.3, 1.9e17): |
|
|
|
with self.subTest(x=x): |
|
|
|
self.assertEqual(self.nroot(x**3, 3), x) |
|
|
|
self.assertEqual(self.nroot(x**8, 8), x) |
|
|
|
self.assertEqual(self.nroot(x**11, 11), x) |
|
|
|
|
|
|
|
|
|
|
|
class Test_NthRoot_NS(unittest.TestCase): |
|
|
|
"""Test internals of the nth_root function, hidden in _nroot_NS.""" |
|
|
|
|
|
|
|
def test_class_cannot_be_instantiated(self): |
|
|
|
# Test that _nroot_NS cannot be instantiated. |
|
|
|
# It should be a namespace, like in C++ or C#, but Python |
|
|
|
# lacks that feature and so we have to make do with a class. |
|
|
|
self.assertRaises(TypeError, statistics._nroot_NS) |
|
|
|
|
|
|
|
|
|
|
|
# === Tests for public functions === |
|
|
|
|
|
|
|
class UnivariateCommonMixin: |
|
|
|
|