blob: dff0cd4476b4a7114e7a1284cf2410534cf24dc8 [file] [log] [blame]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001"""Test suite for statistics module, including helper NumericTestCase and
2approx_equal function.
3
4"""
5
6import collections
7import decimal
8import doctest
9import math
10import random
Serhiy Storchakab12cb6a2013-12-08 18:16:18 +020011import sys
Larry Hastingsf5e987b2013-10-19 11:50:09 -070012import unittest
13
14from decimal import Decimal
15from fractions import Fraction
16
17
18# Module to be tested.
19import statistics
20
21
22# === Helper functions and class ===
23
Steven D'Apranoa474afd2016-08-09 12:49:01 +100024def sign(x):
25 """Return -1.0 for negatives, including -0.0, otherwise +1.0."""
26 return math.copysign(1, x)
27
Steven D'Apranob28c3272015-12-01 19:59:53 +110028def _nan_equal(a, b):
29 """Return True if a and b are both the same kind of NAN.
30
31 >>> _nan_equal(Decimal('NAN'), Decimal('NAN'))
32 True
33 >>> _nan_equal(Decimal('sNAN'), Decimal('sNAN'))
34 True
35 >>> _nan_equal(Decimal('NAN'), Decimal('sNAN'))
36 False
37 >>> _nan_equal(Decimal(42), Decimal('NAN'))
38 False
39
40 >>> _nan_equal(float('NAN'), float('NAN'))
41 True
42 >>> _nan_equal(float('NAN'), 0.5)
43 False
44
45 >>> _nan_equal(float('NAN'), Decimal('NAN'))
46 False
47
48 NAN payloads are not compared.
49 """
50 if type(a) is not type(b):
51 return False
52 if isinstance(a, float):
53 return math.isnan(a) and math.isnan(b)
54 aexp = a.as_tuple()[2]
55 bexp = b.as_tuple()[2]
56 return (aexp == bexp) and (aexp in ('n', 'N')) # Both NAN or both sNAN.
57
58
Larry Hastingsf5e987b2013-10-19 11:50:09 -070059def _calc_errors(actual, expected):
60 """Return the absolute and relative errors between two numbers.
61
62 >>> _calc_errors(100, 75)
63 (25, 0.25)
64 >>> _calc_errors(100, 100)
65 (0, 0.0)
66
67 Returns the (absolute error, relative error) between the two arguments.
68 """
69 base = max(abs(actual), abs(expected))
70 abs_err = abs(actual - expected)
71 rel_err = abs_err/base if base else float('inf')
72 return (abs_err, rel_err)
73
74
75def approx_equal(x, y, tol=1e-12, rel=1e-7):
76 """approx_equal(x, y [, tol [, rel]]) => True|False
77
78 Return True if numbers x and y are approximately equal, to within some
79 margin of error, otherwise return False. Numbers which compare equal
80 will also compare approximately equal.
81
82 x is approximately equal to y if the difference between them is less than
83 an absolute error tol or a relative error rel, whichever is bigger.
84
85 If given, both tol and rel must be finite, non-negative numbers. If not
86 given, default values are tol=1e-12 and rel=1e-7.
87
88 >>> approx_equal(1.2589, 1.2587, tol=0.0003, rel=0)
89 True
90 >>> approx_equal(1.2589, 1.2587, tol=0.0001, rel=0)
91 False
92
93 Absolute error is defined as abs(x-y); if that is less than or equal to
94 tol, x and y are considered approximately equal.
95
96 Relative error is defined as abs((x-y)/x) or abs((x-y)/y), whichever is
97 smaller, provided x or y are not zero. If that figure is less than or
98 equal to rel, x and y are considered approximately equal.
99
100 Complex numbers are not directly supported. If you wish to compare to
101 complex numbers, extract their real and imaginary parts and compare them
102 individually.
103
104 NANs always compare unequal, even with themselves. Infinities compare
105 approximately equal if they have the same sign (both positive or both
106 negative). Infinities with different signs compare unequal; so do
107 comparisons of infinities with finite numbers.
108 """
109 if tol < 0 or rel < 0:
110 raise ValueError('error tolerances must be non-negative')
111 # NANs are never equal to anything, approximately or otherwise.
112 if math.isnan(x) or math.isnan(y):
113 return False
114 # Numbers which compare equal also compare approximately equal.
115 if x == y:
116 # This includes the case of two infinities with the same sign.
117 return True
118 if math.isinf(x) or math.isinf(y):
119 # This includes the case of two infinities of opposite sign, or
120 # one infinity and one finite number.
121 return False
122 # Two finite numbers.
123 actual_error = abs(x - y)
124 allowed_error = max(tol, rel*max(abs(x), abs(y)))
125 return actual_error <= allowed_error
126
127
128# This class exists only as somewhere to stick a docstring containing
129# doctests. The following docstring and tests were originally in a separate
130# module. Now that it has been merged in here, I need somewhere to hang the.
131# docstring. Ultimately, this class will die, and the information below will
132# either become redundant, or be moved into more appropriate places.
133class _DoNothing:
134 """
135 When doing numeric work, especially with floats, exact equality is often
136 not what you want. Due to round-off error, it is often a bad idea to try
137 to compare floats with equality. Instead the usual procedure is to test
138 them with some (hopefully small!) allowance for error.
139
140 The ``approx_equal`` function allows you to specify either an absolute
141 error tolerance, or a relative error, or both.
142
143 Absolute error tolerances are simple, but you need to know the magnitude
144 of the quantities being compared:
145
146 >>> approx_equal(12.345, 12.346, tol=1e-3)
147 True
148 >>> approx_equal(12.345e6, 12.346e6, tol=1e-3) # tol is too small.
149 False
150
151 Relative errors are more suitable when the values you are comparing can
152 vary in magnitude:
153
154 >>> approx_equal(12.345, 12.346, rel=1e-4)
155 True
156 >>> approx_equal(12.345e6, 12.346e6, rel=1e-4)
157 True
158
159 but a naive implementation of relative error testing can run into trouble
160 around zero.
161
162 If you supply both an absolute tolerance and a relative error, the
163 comparison succeeds if either individual test succeeds:
164
165 >>> approx_equal(12.345e6, 12.346e6, tol=1e-3, rel=1e-4)
166 True
167
168 """
169 pass
170
171
172
173# We prefer this for testing numeric values that may not be exactly equal,
174# and avoid using TestCase.assertAlmostEqual, because it sucks :-)
175
176class NumericTestCase(unittest.TestCase):
177 """Unit test class for numeric work.
178
179 This subclasses TestCase. In addition to the standard method
180 ``TestCase.assertAlmostEqual``, ``assertApproxEqual`` is provided.
181 """
182 # By default, we expect exact equality, unless overridden.
183 tol = rel = 0
184
185 def assertApproxEqual(
186 self, first, second, tol=None, rel=None, msg=None
187 ):
188 """Test passes if ``first`` and ``second`` are approximately equal.
189
190 This test passes if ``first`` and ``second`` are equal to
191 within ``tol``, an absolute error, or ``rel``, a relative error.
192
193 If either ``tol`` or ``rel`` are None or not given, they default to
194 test attributes of the same name (by default, 0).
195
196 The objects may be either numbers, or sequences of numbers. Sequences
197 are tested element-by-element.
198
199 >>> class MyTest(NumericTestCase):
200 ... def test_number(self):
201 ... x = 1.0/6
202 ... y = sum([x]*6)
203 ... self.assertApproxEqual(y, 1.0, tol=1e-15)
204 ... def test_sequence(self):
205 ... a = [1.001, 1.001e-10, 1.001e10]
206 ... b = [1.0, 1e-10, 1e10]
207 ... self.assertApproxEqual(a, b, rel=1e-3)
208 ...
209 >>> import unittest
210 >>> from io import StringIO # Suppress test runner output.
211 >>> suite = unittest.TestLoader().loadTestsFromTestCase(MyTest)
212 >>> unittest.TextTestRunner(stream=StringIO()).run(suite)
213 <unittest.runner.TextTestResult run=2 errors=0 failures=0>
214
215 """
216 if tol is None:
217 tol = self.tol
218 if rel is None:
219 rel = self.rel
220 if (
221 isinstance(first, collections.Sequence) and
222 isinstance(second, collections.Sequence)
223 ):
224 check = self._check_approx_seq
225 else:
226 check = self._check_approx_num
227 check(first, second, tol, rel, msg)
228
229 def _check_approx_seq(self, first, second, tol, rel, msg):
230 if len(first) != len(second):
231 standardMsg = (
232 "sequences differ in length: %d items != %d items"
233 % (len(first), len(second))
234 )
235 msg = self._formatMessage(msg, standardMsg)
236 raise self.failureException(msg)
237 for i, (a,e) in enumerate(zip(first, second)):
238 self._check_approx_num(a, e, tol, rel, msg, i)
239
240 def _check_approx_num(self, first, second, tol, rel, msg, idx=None):
241 if approx_equal(first, second, tol, rel):
242 # Test passes. Return early, we are done.
243 return None
244 # Otherwise we failed.
245 standardMsg = self._make_std_err_msg(first, second, tol, rel, idx)
246 msg = self._formatMessage(msg, standardMsg)
247 raise self.failureException(msg)
248
249 @staticmethod
250 def _make_std_err_msg(first, second, tol, rel, idx):
251 # Create the standard error message for approx_equal failures.
252 assert first != second
253 template = (
254 ' %r != %r\n'
255 ' values differ by more than tol=%r and rel=%r\n'
256 ' -> absolute error = %r\n'
257 ' -> relative error = %r'
258 )
259 if idx is not None:
260 header = 'numeric sequences first differ at index %d.\n' % idx
261 template = header + template
262 # Calculate actual errors:
263 abs_err, rel_err = _calc_errors(first, second)
264 return template % (first, second, tol, rel, abs_err, rel_err)
265
266
267# ========================
268# === Test the helpers ===
269# ========================
270
Steven D'Apranoa474afd2016-08-09 12:49:01 +1000271class TestSign(unittest.TestCase):
272 """Test that the helper function sign() works correctly."""
273 def testZeroes(self):
274 # Test that signed zeroes report their sign correctly.
275 self.assertEqual(sign(0.0), +1)
276 self.assertEqual(sign(-0.0), -1)
277
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700278
279# --- Tests for approx_equal ---
280
281class ApproxEqualSymmetryTest(unittest.TestCase):
282 # Test symmetry of approx_equal.
283
284 def test_relative_symmetry(self):
285 # Check that approx_equal treats relative error symmetrically.
286 # (a-b)/a is usually not equal to (a-b)/b. Ensure that this
287 # doesn't matter.
288 #
289 # Note: the reason for this test is that an early version
290 # of approx_equal was not symmetric. A relative error test
291 # would pass, or fail, depending on which value was passed
292 # as the first argument.
293 #
294 args1 = [2456, 37.8, -12.45, Decimal('2.54'), Fraction(17, 54)]
295 args2 = [2459, 37.2, -12.41, Decimal('2.59'), Fraction(15, 54)]
296 assert len(args1) == len(args2)
297 for a, b in zip(args1, args2):
298 self.do_relative_symmetry(a, b)
299
300 def do_relative_symmetry(self, a, b):
301 a, b = min(a, b), max(a, b)
302 assert a < b
303 delta = b - a # The absolute difference between the values.
304 rel_err1, rel_err2 = abs(delta/a), abs(delta/b)
305 # Choose an error margin halfway between the two.
306 rel = (rel_err1 + rel_err2)/2
307 # Now see that values a and b compare approx equal regardless of
308 # which is given first.
309 self.assertTrue(approx_equal(a, b, tol=0, rel=rel))
310 self.assertTrue(approx_equal(b, a, tol=0, rel=rel))
311
312 def test_symmetry(self):
313 # Test that approx_equal(a, b) == approx_equal(b, a)
314 args = [-23, -2, 5, 107, 93568]
315 delta = 2
Christian Heimesad393602013-11-26 01:32:15 +0100316 for a in args:
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700317 for type_ in (int, float, Decimal, Fraction):
Christian Heimesad393602013-11-26 01:32:15 +0100318 x = type_(a)*100
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700319 y = x + delta
320 r = abs(delta/max(x, y))
321 # There are five cases to check:
322 # 1) actual error <= tol, <= rel
323 self.do_symmetry_test(x, y, tol=delta, rel=r)
324 self.do_symmetry_test(x, y, tol=delta+1, rel=2*r)
325 # 2) actual error > tol, > rel
326 self.do_symmetry_test(x, y, tol=delta-1, rel=r/2)
327 # 3) actual error <= tol, > rel
328 self.do_symmetry_test(x, y, tol=delta, rel=r/2)
329 # 4) actual error > tol, <= rel
330 self.do_symmetry_test(x, y, tol=delta-1, rel=r)
331 self.do_symmetry_test(x, y, tol=delta-1, rel=2*r)
332 # 5) exact equality test
333 self.do_symmetry_test(x, x, tol=0, rel=0)
334 self.do_symmetry_test(x, y, tol=0, rel=0)
335
336 def do_symmetry_test(self, a, b, tol, rel):
337 template = "approx_equal comparisons don't match for %r"
338 flag1 = approx_equal(a, b, tol, rel)
339 flag2 = approx_equal(b, a, tol, rel)
340 self.assertEqual(flag1, flag2, template.format((a, b, tol, rel)))
341
342
343class ApproxEqualExactTest(unittest.TestCase):
344 # Test the approx_equal function with exactly equal values.
345 # Equal values should compare as approximately equal.
346 # Test cases for exactly equal values, which should compare approx
347 # equal regardless of the error tolerances given.
348
349 def do_exactly_equal_test(self, x, tol, rel):
350 result = approx_equal(x, x, tol=tol, rel=rel)
351 self.assertTrue(result, 'equality failure for x=%r' % x)
352 result = approx_equal(-x, -x, tol=tol, rel=rel)
353 self.assertTrue(result, 'equality failure for x=%r' % -x)
354
355 def test_exactly_equal_ints(self):
356 # Test that equal int values are exactly equal.
357 for n in [42, 19740, 14974, 230, 1795, 700245, 36587]:
358 self.do_exactly_equal_test(n, 0, 0)
359
360 def test_exactly_equal_floats(self):
361 # Test that equal float values are exactly equal.
362 for x in [0.42, 1.9740, 1497.4, 23.0, 179.5, 70.0245, 36.587]:
363 self.do_exactly_equal_test(x, 0, 0)
364
365 def test_exactly_equal_fractions(self):
366 # Test that equal Fraction values are exactly equal.
367 F = Fraction
368 for f in [F(1, 2), F(0), F(5, 3), F(9, 7), F(35, 36), F(3, 7)]:
369 self.do_exactly_equal_test(f, 0, 0)
370
371 def test_exactly_equal_decimals(self):
372 # Test that equal Decimal values are exactly equal.
373 D = Decimal
374 for d in map(D, "8.2 31.274 912.04 16.745 1.2047".split()):
375 self.do_exactly_equal_test(d, 0, 0)
376
377 def test_exactly_equal_absolute(self):
378 # Test that equal values are exactly equal with an absolute error.
379 for n in [16, 1013, 1372, 1198, 971, 4]:
380 # Test as ints.
381 self.do_exactly_equal_test(n, 0.01, 0)
382 # Test as floats.
383 self.do_exactly_equal_test(n/10, 0.01, 0)
384 # Test as Fractions.
385 f = Fraction(n, 1234)
386 self.do_exactly_equal_test(f, 0.01, 0)
387
388 def test_exactly_equal_absolute_decimals(self):
389 # Test equal Decimal values are exactly equal with an absolute error.
390 self.do_exactly_equal_test(Decimal("3.571"), Decimal("0.01"), 0)
391 self.do_exactly_equal_test(-Decimal("81.3971"), Decimal("0.01"), 0)
392
393 def test_exactly_equal_relative(self):
394 # Test that equal values are exactly equal with a relative error.
395 for x in [8347, 101.3, -7910.28, Fraction(5, 21)]:
396 self.do_exactly_equal_test(x, 0, 0.01)
397 self.do_exactly_equal_test(Decimal("11.68"), 0, Decimal("0.01"))
398
399 def test_exactly_equal_both(self):
400 # Test that equal values are equal when both tol and rel are given.
401 for x in [41017, 16.742, -813.02, Fraction(3, 8)]:
402 self.do_exactly_equal_test(x, 0.1, 0.01)
403 D = Decimal
404 self.do_exactly_equal_test(D("7.2"), D("0.1"), D("0.01"))
405
406
407class ApproxEqualUnequalTest(unittest.TestCase):
408 # Unequal values should compare unequal with zero error tolerances.
409 # Test cases for unequal values, with exact equality test.
410
411 def do_exactly_unequal_test(self, x):
412 for a in (x, -x):
413 result = approx_equal(a, a+1, tol=0, rel=0)
414 self.assertFalse(result, 'inequality failure for x=%r' % a)
415
416 def test_exactly_unequal_ints(self):
417 # Test unequal int values are unequal with zero error tolerance.
418 for n in [951, 572305, 478, 917, 17240]:
419 self.do_exactly_unequal_test(n)
420
421 def test_exactly_unequal_floats(self):
422 # Test unequal float values are unequal with zero error tolerance.
423 for x in [9.51, 5723.05, 47.8, 9.17, 17.24]:
424 self.do_exactly_unequal_test(x)
425
426 def test_exactly_unequal_fractions(self):
427 # Test that unequal Fractions are unequal with zero error tolerance.
428 F = Fraction
429 for f in [F(1, 5), F(7, 9), F(12, 11), F(101, 99023)]:
430 self.do_exactly_unequal_test(f)
431
432 def test_exactly_unequal_decimals(self):
433 # Test that unequal Decimals are unequal with zero error tolerance.
434 for d in map(Decimal, "3.1415 298.12 3.47 18.996 0.00245".split()):
435 self.do_exactly_unequal_test(d)
436
437
438class ApproxEqualInexactTest(unittest.TestCase):
439 # Inexact test cases for approx_error.
440 # Test cases when comparing two values that are not exactly equal.
441
442 # === Absolute error tests ===
443
444 def do_approx_equal_abs_test(self, x, delta):
445 template = "Test failure for x={!r}, y={!r}"
446 for y in (x + delta, x - delta):
447 msg = template.format(x, y)
448 self.assertTrue(approx_equal(x, y, tol=2*delta, rel=0), msg)
449 self.assertFalse(approx_equal(x, y, tol=delta/2, rel=0), msg)
450
451 def test_approx_equal_absolute_ints(self):
452 # Test approximate equality of ints with an absolute error.
453 for n in [-10737, -1975, -7, -2, 0, 1, 9, 37, 423, 9874, 23789110]:
454 self.do_approx_equal_abs_test(n, 10)
455 self.do_approx_equal_abs_test(n, 2)
456
457 def test_approx_equal_absolute_floats(self):
458 # Test approximate equality of floats with an absolute error.
459 for x in [-284.126, -97.1, -3.4, -2.15, 0.5, 1.0, 7.8, 4.23, 3817.4]:
460 self.do_approx_equal_abs_test(x, 1.5)
461 self.do_approx_equal_abs_test(x, 0.01)
462 self.do_approx_equal_abs_test(x, 0.0001)
463
464 def test_approx_equal_absolute_fractions(self):
465 # Test approximate equality of Fractions with an absolute error.
466 delta = Fraction(1, 29)
467 numerators = [-84, -15, -2, -1, 0, 1, 5, 17, 23, 34, 71]
468 for f in (Fraction(n, 29) for n in numerators):
469 self.do_approx_equal_abs_test(f, delta)
470 self.do_approx_equal_abs_test(f, float(delta))
471
472 def test_approx_equal_absolute_decimals(self):
473 # Test approximate equality of Decimals with an absolute error.
474 delta = Decimal("0.01")
475 for d in map(Decimal, "1.0 3.5 36.08 61.79 7912.3648".split()):
476 self.do_approx_equal_abs_test(d, delta)
477 self.do_approx_equal_abs_test(-d, delta)
478
479 def test_cross_zero(self):
480 # Test for the case of the two values having opposite signs.
481 self.assertTrue(approx_equal(1e-5, -1e-5, tol=1e-4, rel=0))
482
483 # === Relative error tests ===
484
485 def do_approx_equal_rel_test(self, x, delta):
486 template = "Test failure for x={!r}, y={!r}"
487 for y in (x*(1+delta), x*(1-delta)):
488 msg = template.format(x, y)
489 self.assertTrue(approx_equal(x, y, tol=0, rel=2*delta), msg)
490 self.assertFalse(approx_equal(x, y, tol=0, rel=delta/2), msg)
491
492 def test_approx_equal_relative_ints(self):
493 # Test approximate equality of ints with a relative error.
494 self.assertTrue(approx_equal(64, 47, tol=0, rel=0.36))
495 self.assertTrue(approx_equal(64, 47, tol=0, rel=0.37))
496 # ---
497 self.assertTrue(approx_equal(449, 512, tol=0, rel=0.125))
498 self.assertTrue(approx_equal(448, 512, tol=0, rel=0.125))
499 self.assertFalse(approx_equal(447, 512, tol=0, rel=0.125))
500
501 def test_approx_equal_relative_floats(self):
502 # Test approximate equality of floats with a relative error.
503 for x in [-178.34, -0.1, 0.1, 1.0, 36.97, 2847.136, 9145.074]:
504 self.do_approx_equal_rel_test(x, 0.02)
505 self.do_approx_equal_rel_test(x, 0.0001)
506
507 def test_approx_equal_relative_fractions(self):
508 # Test approximate equality of Fractions with a relative error.
509 F = Fraction
510 delta = Fraction(3, 8)
511 for f in [F(3, 84), F(17, 30), F(49, 50), F(92, 85)]:
512 for d in (delta, float(delta)):
513 self.do_approx_equal_rel_test(f, d)
514 self.do_approx_equal_rel_test(-f, d)
515
516 def test_approx_equal_relative_decimals(self):
517 # Test approximate equality of Decimals with a relative error.
518 for d in map(Decimal, "0.02 1.0 5.7 13.67 94.138 91027.9321".split()):
519 self.do_approx_equal_rel_test(d, Decimal("0.001"))
520 self.do_approx_equal_rel_test(-d, Decimal("0.05"))
521
522 # === Both absolute and relative error tests ===
523
524 # There are four cases to consider:
525 # 1) actual error <= both absolute and relative error
526 # 2) actual error <= absolute error but > relative error
527 # 3) actual error <= relative error but > absolute error
528 # 4) actual error > both absolute and relative error
529
530 def do_check_both(self, a, b, tol, rel, tol_flag, rel_flag):
531 check = self.assertTrue if tol_flag else self.assertFalse
532 check(approx_equal(a, b, tol=tol, rel=0))
533 check = self.assertTrue if rel_flag else self.assertFalse
534 check(approx_equal(a, b, tol=0, rel=rel))
535 check = self.assertTrue if (tol_flag or rel_flag) else self.assertFalse
536 check(approx_equal(a, b, tol=tol, rel=rel))
537
538 def test_approx_equal_both1(self):
539 # Test actual error <= both absolute and relative error.
540 self.do_check_both(7.955, 7.952, 0.004, 3.8e-4, True, True)
541 self.do_check_both(-7.387, -7.386, 0.002, 0.0002, True, True)
542
543 def test_approx_equal_both2(self):
544 # Test actual error <= absolute error but > relative error.
545 self.do_check_both(7.955, 7.952, 0.004, 3.7e-4, True, False)
546
547 def test_approx_equal_both3(self):
548 # Test actual error <= relative error but > absolute error.
549 self.do_check_both(7.955, 7.952, 0.001, 3.8e-4, False, True)
550
551 def test_approx_equal_both4(self):
552 # Test actual error > both absolute and relative error.
553 self.do_check_both(2.78, 2.75, 0.01, 0.001, False, False)
554 self.do_check_both(971.44, 971.47, 0.02, 3e-5, False, False)
555
556
557class ApproxEqualSpecialsTest(unittest.TestCase):
558 # Test approx_equal with NANs and INFs and zeroes.
559
560 def test_inf(self):
561 for type_ in (float, Decimal):
562 inf = type_('inf')
563 self.assertTrue(approx_equal(inf, inf))
564 self.assertTrue(approx_equal(inf, inf, 0, 0))
565 self.assertTrue(approx_equal(inf, inf, 1, 0.01))
566 self.assertTrue(approx_equal(-inf, -inf))
567 self.assertFalse(approx_equal(inf, -inf))
568 self.assertFalse(approx_equal(inf, 1000))
569
570 def test_nan(self):
571 for type_ in (float, Decimal):
572 nan = type_('nan')
573 for other in (nan, type_('inf'), 1000):
574 self.assertFalse(approx_equal(nan, other))
575
576 def test_float_zeroes(self):
577 nzero = math.copysign(0.0, -1)
578 self.assertTrue(approx_equal(nzero, 0.0, tol=0.1, rel=0.1))
579
580 def test_decimal_zeroes(self):
581 nzero = Decimal("-0.0")
582 self.assertTrue(approx_equal(nzero, Decimal(0), tol=0.1, rel=0.1))
583
584
585class TestApproxEqualErrors(unittest.TestCase):
586 # Test error conditions of approx_equal.
587
588 def test_bad_tol(self):
589 # Test negative tol raises.
590 self.assertRaises(ValueError, approx_equal, 100, 100, -1, 0.1)
591
592 def test_bad_rel(self):
593 # Test negative rel raises.
594 self.assertRaises(ValueError, approx_equal, 100, 100, 1, -0.1)
595
596
597# --- Tests for NumericTestCase ---
598
599# The formatting routine that generates the error messages is complex enough
600# that it too needs testing.
601
602class TestNumericTestCase(unittest.TestCase):
603 # The exact wording of NumericTestCase error messages is *not* guaranteed,
604 # but we need to give them some sort of test to ensure that they are
605 # generated correctly. As a compromise, we look for specific substrings
606 # that are expected to be found even if the overall error message changes.
607
608 def do_test(self, args):
609 actual_msg = NumericTestCase._make_std_err_msg(*args)
610 expected = self.generate_substrings(*args)
611 for substring in expected:
612 self.assertIn(substring, actual_msg)
613
614 def test_numerictestcase_is_testcase(self):
615 # Ensure that NumericTestCase actually is a TestCase.
616 self.assertTrue(issubclass(NumericTestCase, unittest.TestCase))
617
618 def test_error_msg_numeric(self):
619 # Test the error message generated for numeric comparisons.
620 args = (2.5, 4.0, 0.5, 0.25, None)
621 self.do_test(args)
622
623 def test_error_msg_sequence(self):
624 # Test the error message generated for sequence comparisons.
625 args = (3.75, 8.25, 1.25, 0.5, 7)
626 self.do_test(args)
627
628 def generate_substrings(self, first, second, tol, rel, idx):
629 """Return substrings we expect to see in error messages."""
630 abs_err, rel_err = _calc_errors(first, second)
631 substrings = [
632 'tol=%r' % tol,
633 'rel=%r' % rel,
634 'absolute error = %r' % abs_err,
635 'relative error = %r' % rel_err,
636 ]
637 if idx is not None:
638 substrings.append('differ at index %d' % idx)
639 return substrings
640
641
642# =======================================
643# === Tests for the statistics module ===
644# =======================================
645
646
647class GlobalsTest(unittest.TestCase):
648 module = statistics
649 expected_metadata = ["__doc__", "__all__"]
650
651 def test_meta(self):
652 # Test for the existence of metadata.
653 for meta in self.expected_metadata:
654 self.assertTrue(hasattr(self.module, meta),
655 "%s not present" % meta)
656
657 def test_check_all(self):
658 # Check everything in __all__ exists and is public.
659 module = self.module
660 for name in module.__all__:
661 # No private names in __all__:
662 self.assertFalse(name.startswith("_"),
663 'private name "%s" in __all__' % name)
664 # And anything in __all__ must exist:
665 self.assertTrue(hasattr(module, name),
666 'missing name "%s" in __all__' % name)
667
668
669class DocTests(unittest.TestCase):
Serhiy Storchakab12cb6a2013-12-08 18:16:18 +0200670 @unittest.skipIf(sys.flags.optimize >= 2,
671 "Docstrings are omitted with -OO and above")
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700672 def test_doc_tests(self):
Steven D'Apranoa474afd2016-08-09 12:49:01 +1000673 failed, tried = doctest.testmod(statistics, optionflags=doctest.ELLIPSIS)
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700674 self.assertGreater(tried, 0)
675 self.assertEqual(failed, 0)
676
677class StatisticsErrorTest(unittest.TestCase):
678 def test_has_exception(self):
679 errmsg = (
680 "Expected StatisticsError to be a ValueError, but got a"
681 " subclass of %r instead."
682 )
683 self.assertTrue(hasattr(statistics, 'StatisticsError'))
684 self.assertTrue(
685 issubclass(statistics.StatisticsError, ValueError),
686 errmsg % statistics.StatisticsError.__base__
687 )
688
689
690# === Tests for private utility functions ===
691
692class ExactRatioTest(unittest.TestCase):
693 # Test _exact_ratio utility.
694
695 def test_int(self):
696 for i in (-20, -3, 0, 5, 99, 10**20):
697 self.assertEqual(statistics._exact_ratio(i), (i, 1))
698
699 def test_fraction(self):
700 numerators = (-5, 1, 12, 38)
701 for n in numerators:
702 f = Fraction(n, 37)
703 self.assertEqual(statistics._exact_ratio(f), (n, 37))
704
705 def test_float(self):
706 self.assertEqual(statistics._exact_ratio(0.125), (1, 8))
707 self.assertEqual(statistics._exact_ratio(1.125), (9, 8))
708 data = [random.uniform(-100, 100) for _ in range(100)]
709 for x in data:
710 num, den = statistics._exact_ratio(x)
711 self.assertEqual(x, num/den)
712
713 def test_decimal(self):
714 D = Decimal
715 _exact_ratio = statistics._exact_ratio
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000716 self.assertEqual(_exact_ratio(D("0.125")), (1, 8))
717 self.assertEqual(_exact_ratio(D("12.345")), (2469, 200))
718 self.assertEqual(_exact_ratio(D("-1.98")), (-99, 50))
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700719
Steven D'Apranob28c3272015-12-01 19:59:53 +1100720 def test_inf(self):
721 INF = float("INF")
722 class MyFloat(float):
723 pass
724 class MyDecimal(Decimal):
725 pass
726 for inf in (INF, -INF):
727 for type_ in (float, MyFloat, Decimal, MyDecimal):
728 x = type_(inf)
729 ratio = statistics._exact_ratio(x)
730 self.assertEqual(ratio, (x, None))
731 self.assertEqual(type(ratio[0]), type_)
732 self.assertTrue(math.isinf(ratio[0]))
733
734 def test_float_nan(self):
735 NAN = float("NAN")
736 class MyFloat(float):
737 pass
738 for nan in (NAN, MyFloat(NAN)):
739 ratio = statistics._exact_ratio(nan)
740 self.assertTrue(math.isnan(ratio[0]))
741 self.assertIs(ratio[1], None)
742 self.assertEqual(type(ratio[0]), type(nan))
743
744 def test_decimal_nan(self):
745 NAN = Decimal("NAN")
746 sNAN = Decimal("sNAN")
747 class MyDecimal(Decimal):
748 pass
749 for nan in (NAN, MyDecimal(NAN), sNAN, MyDecimal(sNAN)):
750 ratio = statistics._exact_ratio(nan)
751 self.assertTrue(_nan_equal(ratio[0], nan))
752 self.assertIs(ratio[1], None)
753 self.assertEqual(type(ratio[0]), type(nan))
754
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700755
756class DecimalToRatioTest(unittest.TestCase):
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000757 # Test _exact_ratio private function.
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700758
Steven D'Apranob28c3272015-12-01 19:59:53 +1100759 def test_infinity(self):
760 # Test that INFs are handled correctly.
761 inf = Decimal('INF')
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000762 self.assertEqual(statistics._exact_ratio(inf), (inf, None))
763 self.assertEqual(statistics._exact_ratio(-inf), (-inf, None))
Steven D'Apranob28c3272015-12-01 19:59:53 +1100764
765 def test_nan(self):
766 # Test that NANs are handled correctly.
767 for nan in (Decimal('NAN'), Decimal('sNAN')):
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000768 num, den = statistics._exact_ratio(nan)
Steven D'Apranob28c3272015-12-01 19:59:53 +1100769 # Because NANs always compare non-equal, we cannot use assertEqual.
770 # Nor can we use an identity test, as we don't guarantee anything
771 # about the object identity.
772 self.assertTrue(_nan_equal(num, nan))
773 self.assertIs(den, None)
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700774
Nick Coghlan4a7668a2014-02-08 23:55:14 +1000775 def test_sign(self):
776 # Test sign is calculated correctly.
777 numbers = [Decimal("9.8765e12"), Decimal("9.8765e-12")]
778 for d in numbers:
779 # First test positive decimals.
780 assert d > 0
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000781 num, den = statistics._exact_ratio(d)
Nick Coghlan4a7668a2014-02-08 23:55:14 +1000782 self.assertGreaterEqual(num, 0)
783 self.assertGreater(den, 0)
784 # Then test negative decimals.
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000785 num, den = statistics._exact_ratio(-d)
Nick Coghlan4a7668a2014-02-08 23:55:14 +1000786 self.assertLessEqual(num, 0)
787 self.assertGreater(den, 0)
788
789 def test_negative_exponent(self):
790 # Test result when the exponent is negative.
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000791 t = statistics._exact_ratio(Decimal("0.1234"))
792 self.assertEqual(t, (617, 5000))
Nick Coghlan4a7668a2014-02-08 23:55:14 +1000793
794 def test_positive_exponent(self):
795 # Test results when the exponent is positive.
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000796 t = statistics._exact_ratio(Decimal("1.234e7"))
Nick Coghlan4a7668a2014-02-08 23:55:14 +1000797 self.assertEqual(t, (12340000, 1))
798
799 def test_regression_20536(self):
800 # Regression test for issue 20536.
801 # See http://bugs.python.org/issue20536
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000802 t = statistics._exact_ratio(Decimal("1e2"))
Nick Coghlan4a7668a2014-02-08 23:55:14 +1000803 self.assertEqual(t, (100, 1))
Steven D'Aprano3b06e242016-05-05 03:54:29 +1000804 t = statistics._exact_ratio(Decimal("1.47e5"))
Nick Coghlan4a7668a2014-02-08 23:55:14 +1000805 self.assertEqual(t, (147000, 1))
806
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700807
Steven D'Apranob28c3272015-12-01 19:59:53 +1100808class IsFiniteTest(unittest.TestCase):
809 # Test _isfinite private function.
Nick Coghlan73afe2a2014-02-08 19:58:04 +1000810
Steven D'Apranob28c3272015-12-01 19:59:53 +1100811 def test_finite(self):
812 # Test that finite numbers are recognised as finite.
813 for x in (5, Fraction(1, 3), 2.5, Decimal("5.5")):
814 self.assertTrue(statistics._isfinite(x))
Nick Coghlan73afe2a2014-02-08 19:58:04 +1000815
Steven D'Apranob28c3272015-12-01 19:59:53 +1100816 def test_infinity(self):
817 # Test that INFs are not recognised as finite.
818 for x in (float("inf"), Decimal("inf")):
819 self.assertFalse(statistics._isfinite(x))
Nick Coghlan73afe2a2014-02-08 19:58:04 +1000820
Steven D'Apranob28c3272015-12-01 19:59:53 +1100821 def test_nan(self):
822 # Test that NANs are not recognised as finite.
823 for x in (float("nan"), Decimal("NAN"), Decimal("sNAN")):
824 self.assertFalse(statistics._isfinite(x))
825
826
827class CoerceTest(unittest.TestCase):
828 # Test that private function _coerce correctly deals with types.
829
830 # The coercion rules are currently an implementation detail, although at
831 # some point that should change. The tests and comments here define the
832 # correct implementation.
833
834 # Pre-conditions of _coerce:
835 #
836 # - The first time _sum calls _coerce, the
837 # - coerce(T, S) will never be called with bool as the first argument;
838 # this is a pre-condition, guarded with an assertion.
839
840 #
841 # - coerce(T, T) will always return T; we assume T is a valid numeric
842 # type. Violate this assumption at your own risk.
843 #
844 # - Apart from as above, bool is treated as if it were actually int.
845 #
846 # - coerce(int, X) and coerce(X, int) return X.
847 # -
848 def test_bool(self):
849 # bool is somewhat special, due to the pre-condition that it is
850 # never given as the first argument to _coerce, and that it cannot
851 # be subclassed. So we test it specially.
852 for T in (int, float, Fraction, Decimal):
853 self.assertIs(statistics._coerce(T, bool), T)
854 class MyClass(T): pass
855 self.assertIs(statistics._coerce(MyClass, bool), MyClass)
856
857 def assertCoerceTo(self, A, B):
858 """Assert that type A coerces to B."""
859 self.assertIs(statistics._coerce(A, B), B)
860 self.assertIs(statistics._coerce(B, A), B)
861
862 def check_coerce_to(self, A, B):
863 """Checks that type A coerces to B, including subclasses."""
864 # Assert that type A is coerced to B.
865 self.assertCoerceTo(A, B)
866 # Subclasses of A are also coerced to B.
867 class SubclassOfA(A): pass
868 self.assertCoerceTo(SubclassOfA, B)
869 # A, and subclasses of A, are coerced to subclasses of B.
870 class SubclassOfB(B): pass
871 self.assertCoerceTo(A, SubclassOfB)
872 self.assertCoerceTo(SubclassOfA, SubclassOfB)
873
874 def assertCoerceRaises(self, A, B):
875 """Assert that coercing A to B, or vice versa, raises TypeError."""
876 self.assertRaises(TypeError, statistics._coerce, (A, B))
877 self.assertRaises(TypeError, statistics._coerce, (B, A))
878
879 def check_type_coercions(self, T):
880 """Check that type T coerces correctly with subclasses of itself."""
881 assert T is not bool
882 # Coercing a type with itself returns the same type.
883 self.assertIs(statistics._coerce(T, T), T)
884 # Coercing a type with a subclass of itself returns the subclass.
885 class U(T): pass
886 class V(T): pass
887 class W(U): pass
888 for typ in (U, V, W):
889 self.assertCoerceTo(T, typ)
890 self.assertCoerceTo(U, W)
891 # Coercing two subclasses that aren't parent/child is an error.
892 self.assertCoerceRaises(U, V)
893 self.assertCoerceRaises(V, W)
894
895 def test_int(self):
896 # Check that int coerces correctly.
897 self.check_type_coercions(int)
898 for typ in (float, Fraction, Decimal):
899 self.check_coerce_to(int, typ)
900
901 def test_fraction(self):
902 # Check that Fraction coerces correctly.
903 self.check_type_coercions(Fraction)
904 self.check_coerce_to(Fraction, float)
905
906 def test_decimal(self):
907 # Check that Decimal coerces correctly.
908 self.check_type_coercions(Decimal)
909
910 def test_float(self):
911 # Check that float coerces correctly.
912 self.check_type_coercions(float)
913
914 def test_non_numeric_types(self):
915 for bad_type in (str, list, type(None), tuple, dict):
916 for good_type in (int, float, Fraction, Decimal):
917 self.assertCoerceRaises(good_type, bad_type)
918
919 def test_incompatible_types(self):
920 # Test that incompatible types raise.
921 for T in (float, Fraction):
922 class MySubclass(T): pass
923 self.assertCoerceRaises(T, Decimal)
924 self.assertCoerceRaises(MySubclass, Decimal)
925
926
927class ConvertTest(unittest.TestCase):
928 # Test private _convert function.
929
930 def check_exact_equal(self, x, y):
931 """Check that x equals y, and has the same type as well."""
932 self.assertEqual(x, y)
933 self.assertIs(type(x), type(y))
934
935 def test_int(self):
936 # Test conversions to int.
937 x = statistics._convert(Fraction(71), int)
938 self.check_exact_equal(x, 71)
939 class MyInt(int): pass
940 x = statistics._convert(Fraction(17), MyInt)
941 self.check_exact_equal(x, MyInt(17))
942
943 def test_fraction(self):
944 # Test conversions to Fraction.
945 x = statistics._convert(Fraction(95, 99), Fraction)
946 self.check_exact_equal(x, Fraction(95, 99))
947 class MyFraction(Fraction):
948 def __truediv__(self, other):
949 return self.__class__(super().__truediv__(other))
950 x = statistics._convert(Fraction(71, 13), MyFraction)
951 self.check_exact_equal(x, MyFraction(71, 13))
952
953 def test_float(self):
954 # Test conversions to float.
955 x = statistics._convert(Fraction(-1, 2), float)
956 self.check_exact_equal(x, -0.5)
957 class MyFloat(float):
958 def __truediv__(self, other):
959 return self.__class__(super().__truediv__(other))
960 x = statistics._convert(Fraction(9, 8), MyFloat)
961 self.check_exact_equal(x, MyFloat(1.125))
962
963 def test_decimal(self):
964 # Test conversions to Decimal.
965 x = statistics._convert(Fraction(1, 40), Decimal)
966 self.check_exact_equal(x, Decimal("0.025"))
967 class MyDecimal(Decimal):
968 def __truediv__(self, other):
969 return self.__class__(super().__truediv__(other))
970 x = statistics._convert(Fraction(-15, 16), MyDecimal)
971 self.check_exact_equal(x, MyDecimal("-0.9375"))
972
973 def test_inf(self):
974 for INF in (float('inf'), Decimal('inf')):
975 for inf in (INF, -INF):
976 x = statistics._convert(inf, type(inf))
977 self.check_exact_equal(x, inf)
978
979 def test_nan(self):
980 for nan in (float('nan'), Decimal('NAN'), Decimal('sNAN')):
981 x = statistics._convert(nan, type(nan))
982 self.assertTrue(_nan_equal(x, nan))
Nick Coghlan73afe2a2014-02-08 19:58:04 +1000983
Larry Hastingsf5e987b2013-10-19 11:50:09 -0700984
Steven D'Apranoa474afd2016-08-09 12:49:01 +1000985class FailNegTest(unittest.TestCase):
986 """Test _fail_neg private function."""
987
988 def test_pass_through(self):
989 # Test that values are passed through unchanged.
990 values = [1, 2.0, Fraction(3), Decimal(4)]
991 new = list(statistics._fail_neg(values))
992 self.assertEqual(values, new)
993
994 def test_negatives_raise(self):
995 # Test that negatives raise an exception.
996 for x in [1, 2.0, Fraction(3), Decimal(4)]:
997 seq = [-x]
998 it = statistics._fail_neg(seq)
999 self.assertRaises(statistics.StatisticsError, next, it)
1000
1001 def test_error_msg(self):
1002 # Test that a given error message is used.
1003 msg = "badness #%d" % random.randint(10000, 99999)
1004 try:
1005 next(statistics._fail_neg([-1], msg))
1006 except statistics.StatisticsError as e:
1007 errmsg = e.args[0]
1008 else:
1009 self.fail("expected exception, but it didn't happen")
1010 self.assertEqual(errmsg, msg)
1011
1012
Steven D'Aprano9a2be912016-08-09 13:58:10 +10001013class Test_Product(NumericTestCase):
1014 """Test the private _product function."""
1015
1016 def test_ints(self):
1017 data = [1, 2, 5, 7, 9]
1018 self.assertEqual(statistics._product(data), (0, 630))
1019 self.assertEqual(statistics._product(data*100), (0, 630**100))
1020
1021 def test_floats(self):
1022 data = [1.0, 2.0, 4.0, 8.0]
1023 self.assertEqual(statistics._product(data), (8, 0.25))
1024
1025 def test_overflow(self):
1026 # Test with floats that overflow.
1027 data = [1e300]*5
1028 self.assertEqual(statistics._product(data), (5980, 0.6928287951283193))
1029
1030 def test_fractions(self):
1031 F = Fraction
1032 data = [F(14, 23), F(69, 1), F(665, 529), F(299, 105), F(1683, 39)]
1033 exp, mant = statistics._product(data)
1034 self.assertEqual(exp, 0)
1035 self.assertEqual(mant, F(2*3*7*11*17*19, 23))
1036 self.assertTrue(isinstance(mant, F))
1037 # Mixed Fraction and int.
1038 data = [3, 25, F(2, 15)]
1039 exp, mant = statistics._product(data)
1040 self.assertEqual(exp, 0)
1041 self.assertEqual(mant, F(10))
1042 self.assertTrue(isinstance(mant, F))
1043
1044 @unittest.expectedFailure
1045 def test_decimal(self):
1046 D = Decimal
1047 data = [D('24.5'), D('17.6'), D('0.025'), D('1.3')]
1048 assert False
1049
1050 def test_mixed_decimal_float(self):
1051 # Test that mixed Decimal and float raises.
1052 self.assertRaises(TypeError, statistics._product, [1.0, Decimal(1)])
1053 self.assertRaises(TypeError, statistics._product, [Decimal(1), 1.0])
1054
1055
Victor Stinnere3f1e8a2016-08-16 22:22:21 +02001056@unittest.skipIf(True, "FIXME: tests known to fail, see issue #27181")
Steven D'Aprano9a2be912016-08-09 13:58:10 +10001057class Test_Nth_Root(NumericTestCase):
1058 """Test the functionality of the private _nth_root function."""
1059
1060 def setUp(self):
1061 self.nroot = statistics._nth_root
1062
1063 # --- Special values (infinities, NANs, zeroes) ---
1064
1065 def test_float_NAN(self):
1066 # Test that the root of a float NAN is a float NAN.
1067 NAN = float('nan')
1068 for n in range(2, 9):
1069 with self.subTest(n=n):
1070 result = self.nroot(NAN, n)
1071 self.assertTrue(math.isnan(result))
1072
1073 def test_decimal_QNAN(self):
1074 # Test the behaviour when taking the root of a Decimal quiet NAN.
1075 NAN = decimal.Decimal('nan')
1076 with decimal.localcontext() as ctx:
1077 ctx.traps[decimal.InvalidOperation] = 1
1078 self.assertRaises(decimal.InvalidOperation, self.nroot, NAN, 5)
1079 ctx.traps[decimal.InvalidOperation] = 0
1080 self.assertTrue(self.nroot(NAN, 5).is_qnan())
1081
1082 def test_decimal_SNAN(self):
1083 # Test that taking the root of a Decimal sNAN always raises.
1084 sNAN = decimal.Decimal('snan')
1085 with decimal.localcontext() as ctx:
1086 ctx.traps[decimal.InvalidOperation] = 1
1087 self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5)
1088 ctx.traps[decimal.InvalidOperation] = 0
1089 self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5)
1090
1091 def test_inf(self):
1092 # Test that the root of infinity is infinity.
1093 for INF in (float('inf'), decimal.Decimal('inf')):
1094 for n in range(2, 9):
1095 with self.subTest(n=n, inf=INF):
1096 self.assertEqual(self.nroot(INF, n), INF)
1097
1098 def testNInf(self):
1099 # Test that the root of -inf is -inf for odd n.
1100 for NINF in (float('-inf'), decimal.Decimal('-inf')):
1101 for n in range(3, 11, 2):
1102 with self.subTest(n=n, inf=NINF):
1103 self.assertEqual(self.nroot(NINF, n), NINF)
1104
1105 # FIXME: need to check Decimal zeroes too.
1106 def test_zero(self):
1107 # Test that the root of +0.0 is +0.0.
1108 for n in range(2, 11):
1109 with self.subTest(n=n):
1110 result = self.nroot(+0.0, n)
1111 self.assertEqual(result, 0.0)
1112 self.assertEqual(sign(result), +1)
1113
1114 # FIXME: need to check Decimal zeroes too.
1115 def test_neg_zero(self):
1116 # Test that the root of -0.0 is -0.0.
1117 for n in range(2, 11):
1118 with self.subTest(n=n):
1119 result = self.nroot(-0.0, n)
1120 self.assertEqual(result, 0.0)
1121 self.assertEqual(sign(result), -1)
1122
1123 # --- Test return types ---
1124
1125 def check_result_type(self, x, n, outtype):
1126 self.assertIsInstance(self.nroot(x, n), outtype)
1127 class MySubclass(type(x)):
1128 pass
1129 self.assertIsInstance(self.nroot(MySubclass(x), n), outtype)
1130
1131 def testDecimal(self):
1132 # Test that Decimal arguments return Decimal results.
1133 self.check_result_type(decimal.Decimal('33.3'), 3, decimal.Decimal)
1134
1135 def testFloat(self):
1136 # Test that other arguments return float results.
1137 for x in (0.2, Fraction(11, 7), 91):
1138 self.check_result_type(x, 6, float)
1139
1140 # --- Test bad input ---
1141
1142 def testBadOrderTypes(self):
1143 # Test that nroot raises correctly when n has the wrong type.
1144 for n in (5.0, 2j, None, 'x', b'x', [], {}, set(), sign):
1145 with self.subTest(n=n):
1146 self.assertRaises(TypeError, self.nroot, 2.5, n)
1147
1148 def testBadOrderValues(self):
1149 # Test that nroot raises correctly when n has a wrong value.
1150 for n in (1, 0, -1, -2, -87):
1151 with self.subTest(n=n):
1152 self.assertRaises(ValueError, self.nroot, 2.5, n)
1153
1154 def testBadTypes(self):
1155 # Test that nroot raises correctly when x has the wrong type.
1156 for x in (None, 'x', b'x', [], {}, set(), sign):
1157 with self.subTest(x=x):
1158 self.assertRaises(TypeError, self.nroot, x, 3)
1159
1160 def testNegativeEvenPower(self):
1161 # Test negative x with even n raises correctly.
1162 x = random.uniform(-20.0, -0.1)
1163 assert x < 0
1164 for n in range(2, 9, 2):
1165 with self.subTest(x=x, n=n):
1166 self.assertRaises(ValueError, self.nroot, x, n)
1167
1168 # --- Test that nroot is never worse than calling math.pow() ---
1169
1170 def check_error_is_no_worse(self, x, n):
1171 y = math.pow(x, n)
1172 with self.subTest(x=x, n=n, y=y):
1173 err1 = abs(self.nroot(y, n) - x)
1174 err2 = abs(math.pow(y, 1.0/n) - x)
1175 self.assertLessEqual(err1, err2)
1176
1177 def testCompareWithPowSmall(self):
1178 # Compare nroot with pow for small values of x.
1179 for i in range(200):
1180 x = random.uniform(1e-9, 1.0-1e-9)
1181 n = random.choice(range(2, 16))
1182 self.check_error_is_no_worse(x, n)
1183
1184 def testCompareWithPowMedium(self):
1185 # Compare nroot with pow for medium-sized values of x.
1186 for i in range(200):
1187 x = random.uniform(1.0, 100.0)
1188 n = random.choice(range(2, 16))
1189 self.check_error_is_no_worse(x, n)
1190
1191 def testCompareWithPowLarge(self):
1192 # Compare nroot with pow for largish values of x.
1193 for i in range(200):
1194 x = random.uniform(100.0, 10000.0)
1195 n = random.choice(range(2, 16))
1196 self.check_error_is_no_worse(x, n)
1197
1198 def testCompareWithPowHuge(self):
1199 # Compare nroot with pow for huge values of x.
1200 for i in range(200):
1201 x = random.uniform(1e20, 1e50)
1202 # We restrict the order here to avoid an Overflow error.
1203 n = random.choice(range(2, 7))
1204 self.check_error_is_no_worse(x, n)
1205
1206 # --- Test for numerically correct answers ---
1207
1208 def testExactPowers(self):
1209 # Test that small integer powers are calculated exactly.
1210 for i in range(1, 51):
1211 for n in range(2, 16):
1212 if (i, n) == (35, 13):
1213 # See testExpectedFailure35p13
1214 continue
1215 with self.subTest(i=i, n=n):
1216 x = i**n
1217 self.assertEqual(self.nroot(x, n), i)
1218
1219 def testExactPowersNegatives(self):
1220 # Test that small negative integer powers are calculated exactly.
1221 for i in range(-1, -51, -1):
1222 for n in range(3, 16, 2):
1223 if (i, n) == (-35, 13):
1224 # See testExpectedFailure35p13
1225 continue
1226 with self.subTest(i=i, n=n):
1227 x = i**n
1228 assert sign(x) == -1
1229 self.assertEqual(self.nroot(x, n), i)
1230
1231 def testExpectedFailure35p13(self):
1232 # Test the expected failure 35**13 is almost exact.
1233 x = 35**13
1234 err = abs(self.nroot(x, 13) - 35)
1235 self.assertLessEqual(err, 0.000000001)
1236 err = abs(self.nroot(-x, 13) + 35)
1237 self.assertLessEqual(err, 0.000000001)
1238
1239 def testOne(self):
1240 # Test that the root of 1.0 is 1.0.
1241 for n in range(2, 11):
1242 with self.subTest(n=n):
1243 self.assertEqual(self.nroot(1.0, n), 1.0)
1244
1245 def testFraction(self):
1246 # Test Fraction results.
1247 x = Fraction(89, 75)
1248 self.assertEqual(self.nroot(x**12, 12), float(x))
1249
1250 def testInt(self):
1251 # Test int results.
1252 x = 276
1253 self.assertEqual(self.nroot(x**24, 24), x)
1254
1255 def testBigInt(self):
1256 # Test that ints too big to convert to floats work.
1257 bignum = 10**20 # That's not that big...
1258 self.assertEqual(self.nroot(bignum**280, 280), bignum)
1259 # Can we make it bigger?
1260 hugenum = bignum**50
1261 # Make sure that it is too big to convert to a float.
1262 try:
1263 y = float(hugenum)
1264 except OverflowError:
1265 pass
1266 else:
1267 raise AssertionError('hugenum is not big enough')
1268 self.assertEqual(self.nroot(hugenum, 50), float(bignum))
1269
1270 def testDecimal(self):
1271 # Test Decimal results.
1272 for s in '3.759 64.027 5234.338'.split():
1273 x = decimal.Decimal(s)
1274 with self.subTest(x=x):
1275 a = self.nroot(x**5, 5)
1276 self.assertEqual(a, x)
1277 a = self.nroot(x**17, 17)
1278 self.assertEqual(a, x)
1279
1280 def testFloat(self):
1281 # Test float results.
1282 for x in (3.04e-16, 18.25, 461.3, 1.9e17):
1283 with self.subTest(x=x):
1284 self.assertEqual(self.nroot(x**3, 3), x)
1285 self.assertEqual(self.nroot(x**8, 8), x)
1286 self.assertEqual(self.nroot(x**11, 11), x)
1287
1288
1289class Test_NthRoot_NS(unittest.TestCase):
1290 """Test internals of the nth_root function, hidden in _nroot_NS."""
1291
1292 def test_class_cannot_be_instantiated(self):
1293 # Test that _nroot_NS cannot be instantiated.
1294 # It should be a namespace, like in C++ or C#, but Python
1295 # lacks that feature and so we have to make do with a class.
1296 self.assertRaises(TypeError, statistics._nroot_NS)
1297
1298
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001299# === Tests for public functions ===
1300
1301class UnivariateCommonMixin:
1302 # Common tests for most univariate functions that take a data argument.
1303
1304 def test_no_args(self):
1305 # Fail if given no arguments.
1306 self.assertRaises(TypeError, self.func)
1307
1308 def test_empty_data(self):
1309 # Fail when the data argument (first argument) is empty.
1310 for empty in ([], (), iter([])):
1311 self.assertRaises(statistics.StatisticsError, self.func, empty)
1312
1313 def prepare_data(self):
1314 """Return int data for various tests."""
1315 data = list(range(10))
1316 while data == sorted(data):
1317 random.shuffle(data)
1318 return data
1319
1320 def test_no_inplace_modifications(self):
1321 # Test that the function does not modify its input data.
1322 data = self.prepare_data()
1323 assert len(data) != 1 # Necessary to avoid infinite loop.
1324 assert data != sorted(data)
1325 saved = data[:]
1326 assert data is not saved
1327 _ = self.func(data)
1328 self.assertListEqual(data, saved, "data has been modified")
1329
1330 def test_order_doesnt_matter(self):
1331 # Test that the order of data points doesn't change the result.
1332
1333 # CAUTION: due to floating point rounding errors, the result actually
1334 # may depend on the order. Consider this test representing an ideal.
1335 # To avoid this test failing, only test with exact values such as ints
1336 # or Fractions.
1337 data = [1, 2, 3, 3, 3, 4, 5, 6]*100
1338 expected = self.func(data)
1339 random.shuffle(data)
1340 actual = self.func(data)
1341 self.assertEqual(expected, actual)
1342
1343 def test_type_of_data_collection(self):
1344 # Test that the type of iterable data doesn't effect the result.
1345 class MyList(list):
1346 pass
1347 class MyTuple(tuple):
1348 pass
1349 def generator(data):
1350 return (obj for obj in data)
1351 data = self.prepare_data()
1352 expected = self.func(data)
1353 for kind in (list, tuple, iter, MyList, MyTuple, generator):
1354 result = self.func(kind(data))
1355 self.assertEqual(result, expected)
1356
1357 def test_range_data(self):
1358 # Test that functions work with range objects.
1359 data = range(20, 50, 3)
1360 expected = self.func(list(data))
1361 self.assertEqual(self.func(data), expected)
1362
1363 def test_bad_arg_types(self):
1364 # Test that function raises when given data of the wrong type.
1365
1366 # Don't roll the following into a loop like this:
1367 # for bad in list_of_bad:
1368 # self.check_for_type_error(bad)
1369 #
1370 # Since assertRaises doesn't show the arguments that caused the test
1371 # failure, it is very difficult to debug these test failures when the
1372 # following are in a loop.
1373 self.check_for_type_error(None)
1374 self.check_for_type_error(23)
1375 self.check_for_type_error(42.0)
1376 self.check_for_type_error(object())
1377
1378 def check_for_type_error(self, *args):
1379 self.assertRaises(TypeError, self.func, *args)
1380
1381 def test_type_of_data_element(self):
1382 # Check the type of data elements doesn't affect the numeric result.
1383 # This is a weaker test than UnivariateTypeMixin.testTypesConserved,
1384 # because it checks the numeric result by equality, but not by type.
1385 class MyFloat(float):
1386 def __truediv__(self, other):
1387 return type(self)(super().__truediv__(other))
1388 def __add__(self, other):
1389 return type(self)(super().__add__(other))
1390 __radd__ = __add__
1391
1392 raw = self.prepare_data()
1393 expected = self.func(raw)
1394 for kind in (float, MyFloat, Decimal, Fraction):
1395 data = [kind(x) for x in raw]
1396 result = type(expected)(self.func(data))
1397 self.assertEqual(result, expected)
1398
1399
1400class UnivariateTypeMixin:
1401 """Mixin class for type-conserving functions.
1402
1403 This mixin class holds test(s) for functions which conserve the type of
1404 individual data points. E.g. the mean of a list of Fractions should itself
1405 be a Fraction.
1406
1407 Not all tests to do with types need go in this class. Only those that
1408 rely on the function returning the same type as its input data.
1409 """
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001410 def prepare_types_for_conservation_test(self):
1411 """Return the types which are expected to be conserved."""
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001412 class MyFloat(float):
1413 def __truediv__(self, other):
1414 return type(self)(super().__truediv__(other))
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001415 def __rtruediv__(self, other):
1416 return type(self)(super().__rtruediv__(other))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001417 def __sub__(self, other):
1418 return type(self)(super().__sub__(other))
1419 def __rsub__(self, other):
1420 return type(self)(super().__rsub__(other))
1421 def __pow__(self, other):
1422 return type(self)(super().__pow__(other))
1423 def __add__(self, other):
1424 return type(self)(super().__add__(other))
1425 __radd__ = __add__
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001426 return (float, Decimal, Fraction, MyFloat)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001427
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001428 def test_types_conserved(self):
1429 # Test that functions keeps the same type as their data points.
1430 # (Excludes mixed data types.) This only tests the type of the return
1431 # result, not the value.
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001432 data = self.prepare_data()
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001433 for kind in self.prepare_types_for_conservation_test():
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001434 d = [kind(x) for x in data]
1435 result = self.func(d)
1436 self.assertIs(type(result), kind)
1437
1438
Steven D'Apranob28c3272015-12-01 19:59:53 +11001439class TestSumCommon(UnivariateCommonMixin, UnivariateTypeMixin):
1440 # Common test cases for statistics._sum() function.
1441
1442 # This test suite looks only at the numeric value returned by _sum,
1443 # after conversion to the appropriate type.
1444 def setUp(self):
1445 def simplified_sum(*args):
1446 T, value, n = statistics._sum(*args)
1447 return statistics._coerce(value, T)
1448 self.func = simplified_sum
1449
1450
1451class TestSum(NumericTestCase):
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001452 # Test cases for statistics._sum() function.
1453
Steven D'Apranob28c3272015-12-01 19:59:53 +11001454 # These tests look at the entire three value tuple returned by _sum.
1455
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001456 def setUp(self):
1457 self.func = statistics._sum
1458
1459 def test_empty_data(self):
1460 # Override test for empty data.
1461 for data in ([], (), iter([])):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001462 self.assertEqual(self.func(data), (int, Fraction(0), 0))
1463 self.assertEqual(self.func(data, 23), (int, Fraction(23), 0))
1464 self.assertEqual(self.func(data, 2.3), (float, Fraction(2.3), 0))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001465
1466 def test_ints(self):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001467 self.assertEqual(self.func([1, 5, 3, -4, -8, 20, 42, 1]),
1468 (int, Fraction(60), 8))
1469 self.assertEqual(self.func([4, 2, 3, -8, 7], 1000),
1470 (int, Fraction(1008), 5))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001471
1472 def test_floats(self):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001473 self.assertEqual(self.func([0.25]*20),
1474 (float, Fraction(5.0), 20))
1475 self.assertEqual(self.func([0.125, 0.25, 0.5, 0.75], 1.5),
1476 (float, Fraction(3.125), 4))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001477
1478 def test_fractions(self):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001479 self.assertEqual(self.func([Fraction(1, 1000)]*500),
1480 (Fraction, Fraction(1, 2), 500))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001481
1482 def test_decimals(self):
1483 D = Decimal
1484 data = [D("0.001"), D("5.246"), D("1.702"), D("-0.025"),
1485 D("3.974"), D("2.328"), D("4.617"), D("2.843"),
1486 ]
Steven D'Apranob28c3272015-12-01 19:59:53 +11001487 self.assertEqual(self.func(data),
1488 (Decimal, Decimal("20.686"), 8))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001489
1490 def test_compare_with_math_fsum(self):
1491 # Compare with the math.fsum function.
1492 # Ideally we ought to get the exact same result, but sometimes
1493 # we differ by a very slight amount :-(
1494 data = [random.uniform(-100, 1000) for _ in range(1000)]
Steven D'Apranob28c3272015-12-01 19:59:53 +11001495 self.assertApproxEqual(float(self.func(data)[1]), math.fsum(data), rel=2e-16)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001496
1497 def test_start_argument(self):
1498 # Test that the optional start argument works correctly.
1499 data = [random.uniform(1, 1000) for _ in range(100)]
Steven D'Apranob28c3272015-12-01 19:59:53 +11001500 t = self.func(data)[1]
1501 self.assertEqual(t+42, self.func(data, 42)[1])
1502 self.assertEqual(t-23, self.func(data, -23)[1])
1503 self.assertEqual(t+Fraction(1e20), self.func(data, 1e20)[1])
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001504
1505 def test_strings_fail(self):
1506 # Sum of strings should fail.
1507 self.assertRaises(TypeError, self.func, [1, 2, 3], '999')
1508 self.assertRaises(TypeError, self.func, [1, 2, 3, '999'])
1509
1510 def test_bytes_fail(self):
1511 # Sum of bytes should fail.
1512 self.assertRaises(TypeError, self.func, [1, 2, 3], b'999')
1513 self.assertRaises(TypeError, self.func, [1, 2, 3, b'999'])
1514
1515 def test_mixed_sum(self):
Nick Coghlan73afe2a2014-02-08 19:58:04 +10001516 # Mixed input types are not (currently) allowed.
1517 # Check that mixed data types fail.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001518 self.assertRaises(TypeError, self.func, [1, 2.0, Decimal(1)])
Nick Coghlan73afe2a2014-02-08 19:58:04 +10001519 # And so does mixed start argument.
1520 self.assertRaises(TypeError, self.func, [1, 2.0], Decimal(1))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001521
1522
1523class SumTortureTest(NumericTestCase):
1524 def test_torture(self):
1525 # Tim Peters' torture test for sum, and variants of same.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001526 self.assertEqual(statistics._sum([1, 1e100, 1, -1e100]*10000),
1527 (float, Fraction(20000.0), 40000))
1528 self.assertEqual(statistics._sum([1e100, 1, 1, -1e100]*10000),
1529 (float, Fraction(20000.0), 40000))
1530 T, num, count = statistics._sum([1e-100, 1, 1e-100, -1]*10000)
1531 self.assertIs(T, float)
1532 self.assertEqual(count, 40000)
1533 self.assertApproxEqual(float(num), 2.0e-96, rel=5e-16)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001534
1535
1536class SumSpecialValues(NumericTestCase):
1537 # Test that sum works correctly with IEEE-754 special values.
1538
1539 def test_nan(self):
1540 for type_ in (float, Decimal):
1541 nan = type_('nan')
Steven D'Apranob28c3272015-12-01 19:59:53 +11001542 result = statistics._sum([1, nan, 2])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001543 self.assertIs(type(result), type_)
1544 self.assertTrue(math.isnan(result))
1545
1546 def check_infinity(self, x, inf):
1547 """Check x is an infinity of the same type and sign as inf."""
1548 self.assertTrue(math.isinf(x))
1549 self.assertIs(type(x), type(inf))
1550 self.assertEqual(x > 0, inf > 0)
1551 assert x == inf
1552
1553 def do_test_inf(self, inf):
1554 # Adding a single infinity gives infinity.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001555 result = statistics._sum([1, 2, inf, 3])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001556 self.check_infinity(result, inf)
1557 # Adding two infinities of the same sign also gives infinity.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001558 result = statistics._sum([1, 2, inf, 3, inf, 4])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001559 self.check_infinity(result, inf)
1560
1561 def test_float_inf(self):
1562 inf = float('inf')
1563 for sign in (+1, -1):
1564 self.do_test_inf(sign*inf)
1565
1566 def test_decimal_inf(self):
1567 inf = Decimal('inf')
1568 for sign in (+1, -1):
1569 self.do_test_inf(sign*inf)
1570
1571 def test_float_mismatched_infs(self):
1572 # Test that adding two infinities of opposite sign gives a NAN.
1573 inf = float('inf')
Steven D'Apranob28c3272015-12-01 19:59:53 +11001574 result = statistics._sum([1, 2, inf, 3, -inf, 4])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001575 self.assertTrue(math.isnan(result))
1576
Berker Peksagf8c111d2014-09-24 15:03:25 +03001577 def test_decimal_extendedcontext_mismatched_infs_to_nan(self):
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001578 # Test adding Decimal INFs with opposite sign returns NAN.
1579 inf = Decimal('inf')
1580 data = [1, 2, inf, 3, -inf, 4]
1581 with decimal.localcontext(decimal.ExtendedContext):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001582 self.assertTrue(math.isnan(statistics._sum(data)[1]))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001583
Berker Peksagf8c111d2014-09-24 15:03:25 +03001584 def test_decimal_basiccontext_mismatched_infs_to_nan(self):
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001585 # Test adding Decimal INFs with opposite sign raises InvalidOperation.
1586 inf = Decimal('inf')
1587 data = [1, 2, inf, 3, -inf, 4]
1588 with decimal.localcontext(decimal.BasicContext):
1589 self.assertRaises(decimal.InvalidOperation, statistics._sum, data)
1590
1591 def test_decimal_snan_raises(self):
1592 # Adding sNAN should raise InvalidOperation.
1593 sNAN = Decimal('sNAN')
1594 data = [1, sNAN, 2]
1595 self.assertRaises(decimal.InvalidOperation, statistics._sum, data)
1596
1597
1598# === Tests for averages ===
1599
1600class AverageMixin(UnivariateCommonMixin):
1601 # Mixin class holding common tests for averages.
1602
1603 def test_single_value(self):
1604 # Average of a single value is the value itself.
1605 for x in (23, 42.5, 1.3e15, Fraction(15, 19), Decimal('0.28')):
1606 self.assertEqual(self.func([x]), x)
1607
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001608 def prepare_values_for_repeated_single_test(self):
1609 return (3.5, 17, 2.5e15, Fraction(61, 67), Decimal('4.9712'))
1610
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001611 def test_repeated_single_value(self):
1612 # The average of a single repeated value is the value itself.
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001613 for x in self.prepare_values_for_repeated_single_test():
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001614 for count in (2, 5, 10, 20):
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001615 with self.subTest(x=x, count=count):
1616 data = [x]*count
1617 self.assertEqual(self.func(data), x)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001618
1619
1620class TestMean(NumericTestCase, AverageMixin, UnivariateTypeMixin):
1621 def setUp(self):
1622 self.func = statistics.mean
1623
1624 def test_torture_pep(self):
1625 # "Torture Test" from PEP-450.
1626 self.assertEqual(self.func([1e100, 1, 3, -1e100]), 1)
1627
1628 def test_ints(self):
1629 # Test mean with ints.
1630 data = [0, 1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 7, 7, 7, 8, 9]
1631 random.shuffle(data)
1632 self.assertEqual(self.func(data), 4.8125)
1633
1634 def test_floats(self):
1635 # Test mean with floats.
1636 data = [17.25, 19.75, 20.0, 21.5, 21.75, 23.25, 25.125, 27.5]
1637 random.shuffle(data)
1638 self.assertEqual(self.func(data), 22.015625)
1639
1640 def test_decimals(self):
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001641 # Test mean with Decimals.
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001642 D = Decimal
1643 data = [D("1.634"), D("2.517"), D("3.912"), D("4.072"), D("5.813")]
1644 random.shuffle(data)
1645 self.assertEqual(self.func(data), D("3.5896"))
1646
1647 def test_fractions(self):
1648 # Test mean with Fractions.
1649 F = Fraction
1650 data = [F(1, 2), F(2, 3), F(3, 4), F(4, 5), F(5, 6), F(6, 7), F(7, 8)]
1651 random.shuffle(data)
1652 self.assertEqual(self.func(data), F(1479, 1960))
1653
1654 def test_inf(self):
1655 # Test mean with infinities.
1656 raw = [1, 3, 5, 7, 9] # Use only ints, to avoid TypeError later.
1657 for kind in (float, Decimal):
1658 for sign in (1, -1):
1659 inf = kind("inf")*sign
1660 data = raw + [inf]
1661 result = self.func(data)
1662 self.assertTrue(math.isinf(result))
1663 self.assertEqual(result, inf)
1664
1665 def test_mismatched_infs(self):
1666 # Test mean with infinities of opposite sign.
1667 data = [2, 4, 6, float('inf'), 1, 3, 5, float('-inf')]
1668 result = self.func(data)
1669 self.assertTrue(math.isnan(result))
1670
1671 def test_nan(self):
1672 # Test mean with NANs.
1673 raw = [1, 3, 5, 7, 9] # Use only ints, to avoid TypeError later.
1674 for kind in (float, Decimal):
1675 inf = kind("nan")
1676 data = raw + [inf]
1677 result = self.func(data)
1678 self.assertTrue(math.isnan(result))
1679
1680 def test_big_data(self):
1681 # Test adding a large constant to every data point.
1682 c = 1e9
1683 data = [3.4, 4.5, 4.9, 6.7, 6.8, 7.2, 8.0, 8.1, 9.4]
1684 expected = self.func(data) + c
1685 assert expected != c
1686 result = self.func([x+c for x in data])
1687 self.assertEqual(result, expected)
1688
1689 def test_doubled_data(self):
1690 # Mean of [a,b,c...z] should be same as for [a,a,b,b,c,c...z,z].
1691 data = [random.uniform(-3, 5) for _ in range(1000)]
1692 expected = self.func(data)
1693 actual = self.func(data*2)
1694 self.assertApproxEqual(actual, expected)
1695
Nick Coghlan4a7668a2014-02-08 23:55:14 +10001696 def test_regression_20561(self):
1697 # Regression test for issue 20561.
1698 # See http://bugs.python.org/issue20561
1699 d = Decimal('1e4')
1700 self.assertEqual(statistics.mean([d]), d)
1701
Steven D'Apranob28c3272015-12-01 19:59:53 +11001702 def test_regression_25177(self):
1703 # Regression test for issue 25177.
1704 # Ensure very big and very small floats don't overflow.
1705 # See http://bugs.python.org/issue25177.
1706 self.assertEqual(statistics.mean(
1707 [8.988465674311579e+307, 8.98846567431158e+307]),
1708 8.98846567431158e+307)
1709 big = 8.98846567431158e+307
1710 tiny = 5e-324
1711 for n in (2, 3, 5, 200):
1712 self.assertEqual(statistics.mean([big]*n), big)
1713 self.assertEqual(statistics.mean([tiny]*n), tiny)
1714
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001715
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001716class TestHarmonicMean(NumericTestCase, AverageMixin, UnivariateTypeMixin):
1717 def setUp(self):
1718 self.func = statistics.harmonic_mean
1719
1720 def prepare_data(self):
1721 # Override mixin method.
1722 values = super().prepare_data()
1723 values.remove(0)
1724 return values
1725
1726 def prepare_values_for_repeated_single_test(self):
1727 # Override mixin method.
1728 return (3.5, 17, 2.5e15, Fraction(61, 67), Decimal('4.125'))
1729
1730 def test_zero(self):
1731 # Test that harmonic mean returns zero when given zero.
1732 values = [1, 0, 2]
1733 self.assertEqual(self.func(values), 0)
1734
1735 def test_negative_error(self):
1736 # Test that harmonic mean raises when given a negative value.
1737 exc = statistics.StatisticsError
1738 for values in ([-1], [1, -2, 3]):
1739 with self.subTest(values=values):
1740 self.assertRaises(exc, self.func, values)
1741
1742 def test_ints(self):
1743 # Test harmonic mean with ints.
1744 data = [2, 4, 4, 8, 16, 16]
1745 random.shuffle(data)
1746 self.assertEqual(self.func(data), 6*4/5)
1747
1748 def test_floats_exact(self):
1749 # Test harmonic mean with some carefully chosen floats.
1750 data = [1/8, 1/4, 1/4, 1/2, 1/2]
1751 random.shuffle(data)
1752 self.assertEqual(self.func(data), 1/4)
1753 self.assertEqual(self.func([0.25, 0.5, 1.0, 1.0]), 0.5)
1754
1755 def test_singleton_lists(self):
1756 # Test that harmonic mean([x]) returns (approximately) x.
1757 for x in range(1, 101):
Steven D'Apranoe7fef522016-08-09 13:19:48 +10001758 self.assertEqual(self.func([x]), x)
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001759
1760 def test_decimals_exact(self):
1761 # Test harmonic mean with some carefully chosen Decimals.
1762 D = Decimal
1763 self.assertEqual(self.func([D(15), D(30), D(60), D(60)]), D(30))
1764 data = [D("0.05"), D("0.10"), D("0.20"), D("0.20")]
1765 random.shuffle(data)
1766 self.assertEqual(self.func(data), D("0.10"))
1767 data = [D("1.68"), D("0.32"), D("5.94"), D("2.75")]
1768 random.shuffle(data)
1769 self.assertEqual(self.func(data), D(66528)/70723)
1770
1771 def test_fractions(self):
1772 # Test harmonic mean with Fractions.
1773 F = Fraction
1774 data = [F(1, 2), F(2, 3), F(3, 4), F(4, 5), F(5, 6), F(6, 7), F(7, 8)]
1775 random.shuffle(data)
1776 self.assertEqual(self.func(data), F(7*420, 4029))
1777
1778 def test_inf(self):
1779 # Test harmonic mean with infinity.
1780 values = [2.0, float('inf'), 1.0]
1781 self.assertEqual(self.func(values), 2.0)
1782
1783 def test_nan(self):
1784 # Test harmonic mean with NANs.
1785 values = [2.0, float('nan'), 1.0]
1786 self.assertTrue(math.isnan(self.func(values)))
1787
1788 def test_multiply_data_points(self):
1789 # Test multiplying every data point by a constant.
1790 c = 111
1791 data = [3.4, 4.5, 4.9, 6.7, 6.8, 7.2, 8.0, 8.1, 9.4]
1792 expected = self.func(data)*c
1793 result = self.func([x*c for x in data])
1794 self.assertEqual(result, expected)
1795
1796 def test_doubled_data(self):
1797 # Harmonic mean of [a,b...z] should be same as for [a,a,b,b...z,z].
1798 data = [random.uniform(1, 5) for _ in range(1000)]
1799 expected = self.func(data)
1800 actual = self.func(data*2)
1801 self.assertApproxEqual(actual, expected)
1802
1803
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001804class TestMedian(NumericTestCase, AverageMixin):
1805 # Common tests for median and all median.* functions.
1806 def setUp(self):
1807 self.func = statistics.median
1808
1809 def prepare_data(self):
1810 """Overload method from UnivariateCommonMixin."""
1811 data = super().prepare_data()
1812 if len(data)%2 != 1:
1813 data.append(2)
1814 return data
1815
1816 def test_even_ints(self):
1817 # Test median with an even number of int data points.
1818 data = [1, 2, 3, 4, 5, 6]
1819 assert len(data)%2 == 0
1820 self.assertEqual(self.func(data), 3.5)
1821
1822 def test_odd_ints(self):
1823 # Test median with an odd number of int data points.
1824 data = [1, 2, 3, 4, 5, 6, 9]
1825 assert len(data)%2 == 1
1826 self.assertEqual(self.func(data), 4)
1827
1828 def test_odd_fractions(self):
1829 # Test median works with an odd number of Fractions.
1830 F = Fraction
1831 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7)]
1832 assert len(data)%2 == 1
1833 random.shuffle(data)
1834 self.assertEqual(self.func(data), F(3, 7))
1835
1836 def test_even_fractions(self):
1837 # Test median works with an even number of Fractions.
1838 F = Fraction
1839 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7), F(6, 7)]
1840 assert len(data)%2 == 0
1841 random.shuffle(data)
1842 self.assertEqual(self.func(data), F(1, 2))
1843
1844 def test_odd_decimals(self):
1845 # Test median works with an odd number of Decimals.
1846 D = Decimal
1847 data = [D('2.5'), D('3.1'), D('4.2'), D('5.7'), D('5.8')]
1848 assert len(data)%2 == 1
1849 random.shuffle(data)
1850 self.assertEqual(self.func(data), D('4.2'))
1851
1852 def test_even_decimals(self):
1853 # Test median works with an even number of Decimals.
1854 D = Decimal
1855 data = [D('1.2'), D('2.5'), D('3.1'), D('4.2'), D('5.7'), D('5.8')]
1856 assert len(data)%2 == 0
1857 random.shuffle(data)
1858 self.assertEqual(self.func(data), D('3.65'))
1859
1860
1861class TestMedianDataType(NumericTestCase, UnivariateTypeMixin):
1862 # Test conservation of data element type for median.
1863 def setUp(self):
1864 self.func = statistics.median
1865
1866 def prepare_data(self):
1867 data = list(range(15))
1868 assert len(data)%2 == 1
1869 while data == sorted(data):
1870 random.shuffle(data)
1871 return data
1872
1873
1874class TestMedianLow(TestMedian, UnivariateTypeMixin):
1875 def setUp(self):
1876 self.func = statistics.median_low
1877
1878 def test_even_ints(self):
1879 # Test median_low with an even number of ints.
1880 data = [1, 2, 3, 4, 5, 6]
1881 assert len(data)%2 == 0
1882 self.assertEqual(self.func(data), 3)
1883
1884 def test_even_fractions(self):
1885 # Test median_low works with an even number of Fractions.
1886 F = Fraction
1887 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7), F(6, 7)]
1888 assert len(data)%2 == 0
1889 random.shuffle(data)
1890 self.assertEqual(self.func(data), F(3, 7))
1891
1892 def test_even_decimals(self):
1893 # Test median_low works with an even number of Decimals.
1894 D = Decimal
1895 data = [D('1.1'), D('2.2'), D('3.3'), D('4.4'), D('5.5'), D('6.6')]
1896 assert len(data)%2 == 0
1897 random.shuffle(data)
1898 self.assertEqual(self.func(data), D('3.3'))
1899
1900
1901class TestMedianHigh(TestMedian, UnivariateTypeMixin):
1902 def setUp(self):
1903 self.func = statistics.median_high
1904
1905 def test_even_ints(self):
1906 # Test median_high with an even number of ints.
1907 data = [1, 2, 3, 4, 5, 6]
1908 assert len(data)%2 == 0
1909 self.assertEqual(self.func(data), 4)
1910
1911 def test_even_fractions(self):
1912 # Test median_high works with an even number of Fractions.
1913 F = Fraction
1914 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7), F(6, 7)]
1915 assert len(data)%2 == 0
1916 random.shuffle(data)
1917 self.assertEqual(self.func(data), F(4, 7))
1918
1919 def test_even_decimals(self):
1920 # Test median_high works with an even number of Decimals.
1921 D = Decimal
1922 data = [D('1.1'), D('2.2'), D('3.3'), D('4.4'), D('5.5'), D('6.6')]
1923 assert len(data)%2 == 0
1924 random.shuffle(data)
1925 self.assertEqual(self.func(data), D('4.4'))
1926
1927
1928class TestMedianGrouped(TestMedian):
1929 # Test median_grouped.
1930 # Doesn't conserve data element types, so don't use TestMedianType.
1931 def setUp(self):
1932 self.func = statistics.median_grouped
1933
1934 def test_odd_number_repeated(self):
1935 # Test median.grouped with repeated median values.
1936 data = [12, 13, 14, 14, 14, 15, 15]
1937 assert len(data)%2 == 1
1938 self.assertEqual(self.func(data), 14)
1939 #---
1940 data = [12, 13, 14, 14, 14, 14, 15]
1941 assert len(data)%2 == 1
1942 self.assertEqual(self.func(data), 13.875)
1943 #---
1944 data = [5, 10, 10, 15, 20, 20, 20, 20, 25, 25, 30]
1945 assert len(data)%2 == 1
1946 self.assertEqual(self.func(data, 5), 19.375)
1947 #---
1948 data = [16, 18, 18, 18, 18, 20, 20, 20, 22, 22, 22, 24, 24, 26, 28]
1949 assert len(data)%2 == 1
1950 self.assertApproxEqual(self.func(data, 2), 20.66666667, tol=1e-8)
1951
1952 def test_even_number_repeated(self):
1953 # Test median.grouped with repeated median values.
1954 data = [5, 10, 10, 15, 20, 20, 20, 25, 25, 30]
1955 assert len(data)%2 == 0
1956 self.assertApproxEqual(self.func(data, 5), 19.16666667, tol=1e-8)
1957 #---
1958 data = [2, 3, 4, 4, 4, 5]
1959 assert len(data)%2 == 0
1960 self.assertApproxEqual(self.func(data), 3.83333333, tol=1e-8)
1961 #---
1962 data = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6]
1963 assert len(data)%2 == 0
1964 self.assertEqual(self.func(data), 4.5)
1965 #---
1966 data = [3, 4, 4, 4, 5, 5, 5, 5, 6, 6]
1967 assert len(data)%2 == 0
1968 self.assertEqual(self.func(data), 4.75)
1969
1970 def test_repeated_single_value(self):
1971 # Override method from AverageMixin.
1972 # Yet again, failure of median_grouped to conserve the data type
1973 # causes me headaches :-(
1974 for x in (5.3, 68, 4.3e17, Fraction(29, 101), Decimal('32.9714')):
1975 for count in (2, 5, 10, 20):
1976 data = [x]*count
1977 self.assertEqual(self.func(data), float(x))
1978
1979 def test_odd_fractions(self):
1980 # Test median_grouped works with an odd number of Fractions.
1981 F = Fraction
1982 data = [F(5, 4), F(9, 4), F(13, 4), F(13, 4), F(17, 4)]
1983 assert len(data)%2 == 1
1984 random.shuffle(data)
1985 self.assertEqual(self.func(data), 3.0)
1986
1987 def test_even_fractions(self):
1988 # Test median_grouped works with an even number of Fractions.
1989 F = Fraction
1990 data = [F(5, 4), F(9, 4), F(13, 4), F(13, 4), F(17, 4), F(17, 4)]
1991 assert len(data)%2 == 0
1992 random.shuffle(data)
1993 self.assertEqual(self.func(data), 3.25)
1994
1995 def test_odd_decimals(self):
1996 # Test median_grouped works with an odd number of Decimals.
1997 D = Decimal
1998 data = [D('5.5'), D('6.5'), D('6.5'), D('7.5'), D('8.5')]
1999 assert len(data)%2 == 1
2000 random.shuffle(data)
2001 self.assertEqual(self.func(data), 6.75)
2002
2003 def test_even_decimals(self):
2004 # Test median_grouped works with an even number of Decimals.
2005 D = Decimal
2006 data = [D('5.5'), D('5.5'), D('6.5'), D('6.5'), D('7.5'), D('8.5')]
2007 assert len(data)%2 == 0
2008 random.shuffle(data)
2009 self.assertEqual(self.func(data), 6.5)
2010 #---
2011 data = [D('5.5'), D('5.5'), D('6.5'), D('7.5'), D('7.5'), D('8.5')]
2012 assert len(data)%2 == 0
2013 random.shuffle(data)
2014 self.assertEqual(self.func(data), 7.0)
2015
2016 def test_interval(self):
2017 # Test median_grouped with interval argument.
2018 data = [2.25, 2.5, 2.5, 2.75, 2.75, 3.0, 3.0, 3.25, 3.5, 3.75]
2019 self.assertEqual(self.func(data, 0.25), 2.875)
2020 data = [2.25, 2.5, 2.5, 2.75, 2.75, 2.75, 3.0, 3.0, 3.25, 3.5, 3.75]
2021 self.assertApproxEqual(self.func(data, 0.25), 2.83333333, tol=1e-8)
2022 data = [220, 220, 240, 260, 260, 260, 260, 280, 280, 300, 320, 340]
2023 self.assertEqual(self.func(data, 20), 265.0)
2024
Steven D'Aprano8c115a42016-07-08 02:38:45 +10002025 def test_data_type_error(self):
2026 # Test median_grouped with str, bytes data types for data and interval
2027 data = ["", "", ""]
2028 self.assertRaises(TypeError, self.func, data)
2029 #---
2030 data = [b"", b"", b""]
2031 self.assertRaises(TypeError, self.func, data)
2032 #---
2033 data = [1, 2, 3]
2034 interval = ""
2035 self.assertRaises(TypeError, self.func, data, interval)
2036 #---
2037 data = [1, 2, 3]
2038 interval = b""
2039 self.assertRaises(TypeError, self.func, data, interval)
2040
Larry Hastingsf5e987b2013-10-19 11:50:09 -07002041
2042class TestMode(NumericTestCase, AverageMixin, UnivariateTypeMixin):
2043 # Test cases for the discrete version of mode.
2044 def setUp(self):
2045 self.func = statistics.mode
2046
2047 def prepare_data(self):
2048 """Overload method from UnivariateCommonMixin."""
2049 # Make sure test data has exactly one mode.
2050 return [1, 1, 1, 1, 3, 4, 7, 9, 0, 8, 2]
2051
2052 def test_range_data(self):
2053 # Override test from UnivariateCommonMixin.
2054 data = range(20, 50, 3)
2055 self.assertRaises(statistics.StatisticsError, self.func, data)
2056
2057 def test_nominal_data(self):
2058 # Test mode with nominal data.
2059 data = 'abcbdb'
2060 self.assertEqual(self.func(data), 'b')
2061 data = 'fe fi fo fum fi fi'.split()
2062 self.assertEqual(self.func(data), 'fi')
2063
2064 def test_discrete_data(self):
2065 # Test mode with discrete numeric data.
2066 data = list(range(10))
2067 for i in range(10):
2068 d = data + [i]
2069 random.shuffle(d)
2070 self.assertEqual(self.func(d), i)
2071
2072 def test_bimodal_data(self):
2073 # Test mode with bimodal data.
2074 data = [1, 1, 2, 2, 2, 2, 3, 4, 5, 6, 6, 6, 6, 7, 8, 9, 9]
2075 assert data.count(2) == data.count(6) == 4
2076 # Check for an exception.
2077 self.assertRaises(statistics.StatisticsError, self.func, data)
2078
2079 def test_unique_data_failure(self):
2080 # Test mode exception when data points are all unique.
2081 data = list(range(10))
2082 self.assertRaises(statistics.StatisticsError, self.func, data)
2083
2084 def test_none_data(self):
2085 # Test that mode raises TypeError if given None as data.
2086
2087 # This test is necessary because the implementation of mode uses
2088 # collections.Counter, which accepts None and returns an empty dict.
2089 self.assertRaises(TypeError, self.func, None)
2090
Nick Coghlanbfd68bf2014-02-08 19:44:16 +10002091 def test_counter_data(self):
2092 # Test that a Counter is treated like any other iterable.
2093 data = collections.Counter([1, 1, 1, 2])
2094 # Since the keys of the counter are treated as data points, not the
2095 # counts, this should raise.
2096 self.assertRaises(statistics.StatisticsError, self.func, data)
2097
2098
Larry Hastingsf5e987b2013-10-19 11:50:09 -07002099
2100# === Tests for variances and standard deviations ===
2101
2102class VarianceStdevMixin(UnivariateCommonMixin):
2103 # Mixin class holding common tests for variance and std dev.
2104
2105 # Subclasses should inherit from this before NumericTestClass, in order
2106 # to see the rel attribute below. See testShiftData for an explanation.
2107
2108 rel = 1e-12
2109
2110 def test_single_value(self):
2111 # Deviation of a single value is zero.
2112 for x in (11, 19.8, 4.6e14, Fraction(21, 34), Decimal('8.392')):
2113 self.assertEqual(self.func([x]), 0)
2114
2115 def test_repeated_single_value(self):
2116 # The deviation of a single repeated value is zero.
2117 for x in (7.2, 49, 8.1e15, Fraction(3, 7), Decimal('62.4802')):
2118 for count in (2, 3, 5, 15):
2119 data = [x]*count
2120 self.assertEqual(self.func(data), 0)
2121
2122 def test_domain_error_regression(self):
2123 # Regression test for a domain error exception.
2124 # (Thanks to Geremy Condra.)
2125 data = [0.123456789012345]*10000
2126 # All the items are identical, so variance should be exactly zero.
2127 # We allow some small round-off error, but not much.
2128 result = self.func(data)
2129 self.assertApproxEqual(result, 0.0, tol=5e-17)
2130 self.assertGreaterEqual(result, 0) # A negative result must fail.
2131
2132 def test_shift_data(self):
2133 # Test that shifting the data by a constant amount does not affect
2134 # the variance or stdev. Or at least not much.
2135
2136 # Due to rounding, this test should be considered an ideal. We allow
2137 # some tolerance away from "no change at all" by setting tol and/or rel
2138 # attributes. Subclasses may set tighter or looser error tolerances.
2139 raw = [1.03, 1.27, 1.94, 2.04, 2.58, 3.14, 4.75, 4.98, 5.42, 6.78]
2140 expected = self.func(raw)
2141 # Don't set shift too high, the bigger it is, the more rounding error.
2142 shift = 1e5
2143 data = [x + shift for x in raw]
2144 self.assertApproxEqual(self.func(data), expected)
2145
2146 def test_shift_data_exact(self):
2147 # Like test_shift_data, but result is always exact.
2148 raw = [1, 3, 3, 4, 5, 7, 9, 10, 11, 16]
2149 assert all(x==int(x) for x in raw)
2150 expected = self.func(raw)
2151 shift = 10**9
2152 data = [x + shift for x in raw]
2153 self.assertEqual(self.func(data), expected)
2154
2155 def test_iter_list_same(self):
2156 # Test that iter data and list data give the same result.
2157
2158 # This is an explicit test that iterators and lists are treated the
2159 # same; justification for this test over and above the similar test
2160 # in UnivariateCommonMixin is that an earlier design had variance and
2161 # friends swap between one- and two-pass algorithms, which would
2162 # sometimes give different results.
2163 data = [random.uniform(-3, 8) for _ in range(1000)]
2164 expected = self.func(data)
2165 self.assertEqual(self.func(iter(data)), expected)
2166
2167
2168class TestPVariance(VarianceStdevMixin, NumericTestCase, UnivariateTypeMixin):
2169 # Tests for population variance.
2170 def setUp(self):
2171 self.func = statistics.pvariance
2172
2173 def test_exact_uniform(self):
2174 # Test the variance against an exact result for uniform data.
2175 data = list(range(10000))
2176 random.shuffle(data)
2177 expected = (10000**2 - 1)/12 # Exact value.
2178 self.assertEqual(self.func(data), expected)
2179
2180 def test_ints(self):
2181 # Test population variance with int data.
2182 data = [4, 7, 13, 16]
2183 exact = 22.5
2184 self.assertEqual(self.func(data), exact)
2185
2186 def test_fractions(self):
2187 # Test population variance with Fraction data.
2188 F = Fraction
2189 data = [F(1, 4), F(1, 4), F(3, 4), F(7, 4)]
2190 exact = F(3, 8)
2191 result = self.func(data)
2192 self.assertEqual(result, exact)
2193 self.assertIsInstance(result, Fraction)
2194
2195 def test_decimals(self):
2196 # Test population variance with Decimal data.
2197 D = Decimal
2198 data = [D("12.1"), D("12.2"), D("12.5"), D("12.9")]
2199 exact = D('0.096875')
2200 result = self.func(data)
2201 self.assertEqual(result, exact)
2202 self.assertIsInstance(result, Decimal)
2203
2204
2205class TestVariance(VarianceStdevMixin, NumericTestCase, UnivariateTypeMixin):
2206 # Tests for sample variance.
2207 def setUp(self):
2208 self.func = statistics.variance
2209
2210 def test_single_value(self):
2211 # Override method from VarianceStdevMixin.
2212 for x in (35, 24.7, 8.2e15, Fraction(19, 30), Decimal('4.2084')):
2213 self.assertRaises(statistics.StatisticsError, self.func, [x])
2214
2215 def test_ints(self):
2216 # Test sample variance with int data.
2217 data = [4, 7, 13, 16]
2218 exact = 30
2219 self.assertEqual(self.func(data), exact)
2220
2221 def test_fractions(self):
2222 # Test sample variance with Fraction data.
2223 F = Fraction
2224 data = [F(1, 4), F(1, 4), F(3, 4), F(7, 4)]
2225 exact = F(1, 2)
2226 result = self.func(data)
2227 self.assertEqual(result, exact)
2228 self.assertIsInstance(result, Fraction)
2229
2230 def test_decimals(self):
2231 # Test sample variance with Decimal data.
2232 D = Decimal
2233 data = [D(2), D(2), D(7), D(9)]
2234 exact = 4*D('9.5')/D(3)
2235 result = self.func(data)
2236 self.assertEqual(result, exact)
2237 self.assertIsInstance(result, Decimal)
2238
2239
2240class TestPStdev(VarianceStdevMixin, NumericTestCase):
2241 # Tests for population standard deviation.
2242 def setUp(self):
2243 self.func = statistics.pstdev
2244
2245 def test_compare_to_variance(self):
2246 # Test that stdev is, in fact, the square root of variance.
2247 data = [random.uniform(-17, 24) for _ in range(1000)]
2248 expected = math.sqrt(statistics.pvariance(data))
2249 self.assertEqual(self.func(data), expected)
2250
2251
2252class TestStdev(VarianceStdevMixin, NumericTestCase):
2253 # Tests for sample standard deviation.
2254 def setUp(self):
2255 self.func = statistics.stdev
2256
2257 def test_single_value(self):
2258 # Override method from VarianceStdevMixin.
2259 for x in (81, 203.74, 3.9e14, Fraction(5, 21), Decimal('35.719')):
2260 self.assertRaises(statistics.StatisticsError, self.func, [x])
2261
2262 def test_compare_to_variance(self):
2263 # Test that stdev is, in fact, the square root of variance.
2264 data = [random.uniform(-2, 9) for _ in range(1000)]
2265 expected = math.sqrt(statistics.variance(data))
2266 self.assertEqual(self.func(data), expected)
2267
2268
2269# === Run tests ===
2270
2271def load_tests(loader, tests, ignore):
2272 """Used for doctest/unittest integration."""
2273 tests.addTests(doctest.DocTestSuite())
2274 return tests
2275
2276
2277if __name__ == "__main__":
2278 unittest.main()