blob: 8b0c01fd85325503091c2cdc8ab68e62125ec7d1 [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
1056class Test_Nth_Root(NumericTestCase):
1057 """Test the functionality of the private _nth_root function."""
1058
1059 def setUp(self):
1060 self.nroot = statistics._nth_root
1061
1062 # --- Special values (infinities, NANs, zeroes) ---
1063
1064 def test_float_NAN(self):
1065 # Test that the root of a float NAN is a float NAN.
1066 NAN = float('nan')
1067 for n in range(2, 9):
1068 with self.subTest(n=n):
1069 result = self.nroot(NAN, n)
1070 self.assertTrue(math.isnan(result))
1071
1072 def test_decimal_QNAN(self):
1073 # Test the behaviour when taking the root of a Decimal quiet NAN.
1074 NAN = decimal.Decimal('nan')
1075 with decimal.localcontext() as ctx:
1076 ctx.traps[decimal.InvalidOperation] = 1
1077 self.assertRaises(decimal.InvalidOperation, self.nroot, NAN, 5)
1078 ctx.traps[decimal.InvalidOperation] = 0
1079 self.assertTrue(self.nroot(NAN, 5).is_qnan())
1080
1081 def test_decimal_SNAN(self):
1082 # Test that taking the root of a Decimal sNAN always raises.
1083 sNAN = decimal.Decimal('snan')
1084 with decimal.localcontext() as ctx:
1085 ctx.traps[decimal.InvalidOperation] = 1
1086 self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5)
1087 ctx.traps[decimal.InvalidOperation] = 0
1088 self.assertRaises(decimal.InvalidOperation, self.nroot, sNAN, 5)
1089
1090 def test_inf(self):
1091 # Test that the root of infinity is infinity.
1092 for INF in (float('inf'), decimal.Decimal('inf')):
1093 for n in range(2, 9):
1094 with self.subTest(n=n, inf=INF):
1095 self.assertEqual(self.nroot(INF, n), INF)
1096
1097 def testNInf(self):
1098 # Test that the root of -inf is -inf for odd n.
1099 for NINF in (float('-inf'), decimal.Decimal('-inf')):
1100 for n in range(3, 11, 2):
1101 with self.subTest(n=n, inf=NINF):
1102 self.assertEqual(self.nroot(NINF, n), NINF)
1103
1104 # FIXME: need to check Decimal zeroes too.
1105 def test_zero(self):
1106 # Test that the root of +0.0 is +0.0.
1107 for n in range(2, 11):
1108 with self.subTest(n=n):
1109 result = self.nroot(+0.0, n)
1110 self.assertEqual(result, 0.0)
1111 self.assertEqual(sign(result), +1)
1112
1113 # FIXME: need to check Decimal zeroes too.
1114 def test_neg_zero(self):
1115 # Test that the root of -0.0 is -0.0.
1116 for n in range(2, 11):
1117 with self.subTest(n=n):
1118 result = self.nroot(-0.0, n)
1119 self.assertEqual(result, 0.0)
1120 self.assertEqual(sign(result), -1)
1121
1122 # --- Test return types ---
1123
1124 def check_result_type(self, x, n, outtype):
1125 self.assertIsInstance(self.nroot(x, n), outtype)
1126 class MySubclass(type(x)):
1127 pass
1128 self.assertIsInstance(self.nroot(MySubclass(x), n), outtype)
1129
1130 def testDecimal(self):
1131 # Test that Decimal arguments return Decimal results.
1132 self.check_result_type(decimal.Decimal('33.3'), 3, decimal.Decimal)
1133
1134 def testFloat(self):
1135 # Test that other arguments return float results.
1136 for x in (0.2, Fraction(11, 7), 91):
1137 self.check_result_type(x, 6, float)
1138
1139 # --- Test bad input ---
1140
1141 def testBadOrderTypes(self):
1142 # Test that nroot raises correctly when n has the wrong type.
1143 for n in (5.0, 2j, None, 'x', b'x', [], {}, set(), sign):
1144 with self.subTest(n=n):
1145 self.assertRaises(TypeError, self.nroot, 2.5, n)
1146
1147 def testBadOrderValues(self):
1148 # Test that nroot raises correctly when n has a wrong value.
1149 for n in (1, 0, -1, -2, -87):
1150 with self.subTest(n=n):
1151 self.assertRaises(ValueError, self.nroot, 2.5, n)
1152
1153 def testBadTypes(self):
1154 # Test that nroot raises correctly when x has the wrong type.
1155 for x in (None, 'x', b'x', [], {}, set(), sign):
1156 with self.subTest(x=x):
1157 self.assertRaises(TypeError, self.nroot, x, 3)
1158
1159 def testNegativeEvenPower(self):
1160 # Test negative x with even n raises correctly.
1161 x = random.uniform(-20.0, -0.1)
1162 assert x < 0
1163 for n in range(2, 9, 2):
1164 with self.subTest(x=x, n=n):
1165 self.assertRaises(ValueError, self.nroot, x, n)
1166
1167 # --- Test that nroot is never worse than calling math.pow() ---
1168
1169 def check_error_is_no_worse(self, x, n):
1170 y = math.pow(x, n)
1171 with self.subTest(x=x, n=n, y=y):
1172 err1 = abs(self.nroot(y, n) - x)
1173 err2 = abs(math.pow(y, 1.0/n) - x)
1174 self.assertLessEqual(err1, err2)
1175
1176 def testCompareWithPowSmall(self):
1177 # Compare nroot with pow for small values of x.
1178 for i in range(200):
1179 x = random.uniform(1e-9, 1.0-1e-9)
1180 n = random.choice(range(2, 16))
1181 self.check_error_is_no_worse(x, n)
1182
1183 def testCompareWithPowMedium(self):
1184 # Compare nroot with pow for medium-sized values of x.
1185 for i in range(200):
1186 x = random.uniform(1.0, 100.0)
1187 n = random.choice(range(2, 16))
1188 self.check_error_is_no_worse(x, n)
1189
1190 def testCompareWithPowLarge(self):
1191 # Compare nroot with pow for largish values of x.
1192 for i in range(200):
1193 x = random.uniform(100.0, 10000.0)
1194 n = random.choice(range(2, 16))
1195 self.check_error_is_no_worse(x, n)
1196
1197 def testCompareWithPowHuge(self):
1198 # Compare nroot with pow for huge values of x.
1199 for i in range(200):
1200 x = random.uniform(1e20, 1e50)
1201 # We restrict the order here to avoid an Overflow error.
1202 n = random.choice(range(2, 7))
1203 self.check_error_is_no_worse(x, n)
1204
1205 # --- Test for numerically correct answers ---
1206
1207 def testExactPowers(self):
1208 # Test that small integer powers are calculated exactly.
1209 for i in range(1, 51):
1210 for n in range(2, 16):
1211 if (i, n) == (35, 13):
1212 # See testExpectedFailure35p13
1213 continue
1214 with self.subTest(i=i, n=n):
1215 x = i**n
1216 self.assertEqual(self.nroot(x, n), i)
1217
1218 def testExactPowersNegatives(self):
1219 # Test that small negative integer powers are calculated exactly.
1220 for i in range(-1, -51, -1):
1221 for n in range(3, 16, 2):
1222 if (i, n) == (-35, 13):
1223 # See testExpectedFailure35p13
1224 continue
1225 with self.subTest(i=i, n=n):
1226 x = i**n
1227 assert sign(x) == -1
1228 self.assertEqual(self.nroot(x, n), i)
1229
1230 def testExpectedFailure35p13(self):
1231 # Test the expected failure 35**13 is almost exact.
1232 x = 35**13
1233 err = abs(self.nroot(x, 13) - 35)
1234 self.assertLessEqual(err, 0.000000001)
1235 err = abs(self.nroot(-x, 13) + 35)
1236 self.assertLessEqual(err, 0.000000001)
1237
1238 def testOne(self):
1239 # Test that the root of 1.0 is 1.0.
1240 for n in range(2, 11):
1241 with self.subTest(n=n):
1242 self.assertEqual(self.nroot(1.0, n), 1.0)
1243
1244 def testFraction(self):
1245 # Test Fraction results.
1246 x = Fraction(89, 75)
1247 self.assertEqual(self.nroot(x**12, 12), float(x))
1248
1249 def testInt(self):
1250 # Test int results.
1251 x = 276
1252 self.assertEqual(self.nroot(x**24, 24), x)
1253
1254 def testBigInt(self):
1255 # Test that ints too big to convert to floats work.
1256 bignum = 10**20 # That's not that big...
1257 self.assertEqual(self.nroot(bignum**280, 280), bignum)
1258 # Can we make it bigger?
1259 hugenum = bignum**50
1260 # Make sure that it is too big to convert to a float.
1261 try:
1262 y = float(hugenum)
1263 except OverflowError:
1264 pass
1265 else:
1266 raise AssertionError('hugenum is not big enough')
1267 self.assertEqual(self.nroot(hugenum, 50), float(bignum))
1268
1269 def testDecimal(self):
1270 # Test Decimal results.
1271 for s in '3.759 64.027 5234.338'.split():
1272 x = decimal.Decimal(s)
1273 with self.subTest(x=x):
1274 a = self.nroot(x**5, 5)
1275 self.assertEqual(a, x)
1276 a = self.nroot(x**17, 17)
1277 self.assertEqual(a, x)
1278
1279 def testFloat(self):
1280 # Test float results.
1281 for x in (3.04e-16, 18.25, 461.3, 1.9e17):
1282 with self.subTest(x=x):
1283 self.assertEqual(self.nroot(x**3, 3), x)
1284 self.assertEqual(self.nroot(x**8, 8), x)
1285 self.assertEqual(self.nroot(x**11, 11), x)
1286
1287
1288class Test_NthRoot_NS(unittest.TestCase):
1289 """Test internals of the nth_root function, hidden in _nroot_NS."""
1290
1291 def test_class_cannot_be_instantiated(self):
1292 # Test that _nroot_NS cannot be instantiated.
1293 # It should be a namespace, like in C++ or C#, but Python
1294 # lacks that feature and so we have to make do with a class.
1295 self.assertRaises(TypeError, statistics._nroot_NS)
1296
1297
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001298# === Tests for public functions ===
1299
1300class UnivariateCommonMixin:
1301 # Common tests for most univariate functions that take a data argument.
1302
1303 def test_no_args(self):
1304 # Fail if given no arguments.
1305 self.assertRaises(TypeError, self.func)
1306
1307 def test_empty_data(self):
1308 # Fail when the data argument (first argument) is empty.
1309 for empty in ([], (), iter([])):
1310 self.assertRaises(statistics.StatisticsError, self.func, empty)
1311
1312 def prepare_data(self):
1313 """Return int data for various tests."""
1314 data = list(range(10))
1315 while data == sorted(data):
1316 random.shuffle(data)
1317 return data
1318
1319 def test_no_inplace_modifications(self):
1320 # Test that the function does not modify its input data.
1321 data = self.prepare_data()
1322 assert len(data) != 1 # Necessary to avoid infinite loop.
1323 assert data != sorted(data)
1324 saved = data[:]
1325 assert data is not saved
1326 _ = self.func(data)
1327 self.assertListEqual(data, saved, "data has been modified")
1328
1329 def test_order_doesnt_matter(self):
1330 # Test that the order of data points doesn't change the result.
1331
1332 # CAUTION: due to floating point rounding errors, the result actually
1333 # may depend on the order. Consider this test representing an ideal.
1334 # To avoid this test failing, only test with exact values such as ints
1335 # or Fractions.
1336 data = [1, 2, 3, 3, 3, 4, 5, 6]*100
1337 expected = self.func(data)
1338 random.shuffle(data)
1339 actual = self.func(data)
1340 self.assertEqual(expected, actual)
1341
1342 def test_type_of_data_collection(self):
1343 # Test that the type of iterable data doesn't effect the result.
1344 class MyList(list):
1345 pass
1346 class MyTuple(tuple):
1347 pass
1348 def generator(data):
1349 return (obj for obj in data)
1350 data = self.prepare_data()
1351 expected = self.func(data)
1352 for kind in (list, tuple, iter, MyList, MyTuple, generator):
1353 result = self.func(kind(data))
1354 self.assertEqual(result, expected)
1355
1356 def test_range_data(self):
1357 # Test that functions work with range objects.
1358 data = range(20, 50, 3)
1359 expected = self.func(list(data))
1360 self.assertEqual(self.func(data), expected)
1361
1362 def test_bad_arg_types(self):
1363 # Test that function raises when given data of the wrong type.
1364
1365 # Don't roll the following into a loop like this:
1366 # for bad in list_of_bad:
1367 # self.check_for_type_error(bad)
1368 #
1369 # Since assertRaises doesn't show the arguments that caused the test
1370 # failure, it is very difficult to debug these test failures when the
1371 # following are in a loop.
1372 self.check_for_type_error(None)
1373 self.check_for_type_error(23)
1374 self.check_for_type_error(42.0)
1375 self.check_for_type_error(object())
1376
1377 def check_for_type_error(self, *args):
1378 self.assertRaises(TypeError, self.func, *args)
1379
1380 def test_type_of_data_element(self):
1381 # Check the type of data elements doesn't affect the numeric result.
1382 # This is a weaker test than UnivariateTypeMixin.testTypesConserved,
1383 # because it checks the numeric result by equality, but not by type.
1384 class MyFloat(float):
1385 def __truediv__(self, other):
1386 return type(self)(super().__truediv__(other))
1387 def __add__(self, other):
1388 return type(self)(super().__add__(other))
1389 __radd__ = __add__
1390
1391 raw = self.prepare_data()
1392 expected = self.func(raw)
1393 for kind in (float, MyFloat, Decimal, Fraction):
1394 data = [kind(x) for x in raw]
1395 result = type(expected)(self.func(data))
1396 self.assertEqual(result, expected)
1397
1398
1399class UnivariateTypeMixin:
1400 """Mixin class for type-conserving functions.
1401
1402 This mixin class holds test(s) for functions which conserve the type of
1403 individual data points. E.g. the mean of a list of Fractions should itself
1404 be a Fraction.
1405
1406 Not all tests to do with types need go in this class. Only those that
1407 rely on the function returning the same type as its input data.
1408 """
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001409 def prepare_types_for_conservation_test(self):
1410 """Return the types which are expected to be conserved."""
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001411 class MyFloat(float):
1412 def __truediv__(self, other):
1413 return type(self)(super().__truediv__(other))
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001414 def __rtruediv__(self, other):
1415 return type(self)(super().__rtruediv__(other))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001416 def __sub__(self, other):
1417 return type(self)(super().__sub__(other))
1418 def __rsub__(self, other):
1419 return type(self)(super().__rsub__(other))
1420 def __pow__(self, other):
1421 return type(self)(super().__pow__(other))
1422 def __add__(self, other):
1423 return type(self)(super().__add__(other))
1424 __radd__ = __add__
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001425 return (float, Decimal, Fraction, MyFloat)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001426
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001427 def test_types_conserved(self):
1428 # Test that functions keeps the same type as their data points.
1429 # (Excludes mixed data types.) This only tests the type of the return
1430 # result, not the value.
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001431 data = self.prepare_data()
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001432 for kind in self.prepare_types_for_conservation_test():
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001433 d = [kind(x) for x in data]
1434 result = self.func(d)
1435 self.assertIs(type(result), kind)
1436
1437
Steven D'Apranob28c3272015-12-01 19:59:53 +11001438class TestSumCommon(UnivariateCommonMixin, UnivariateTypeMixin):
1439 # Common test cases for statistics._sum() function.
1440
1441 # This test suite looks only at the numeric value returned by _sum,
1442 # after conversion to the appropriate type.
1443 def setUp(self):
1444 def simplified_sum(*args):
1445 T, value, n = statistics._sum(*args)
1446 return statistics._coerce(value, T)
1447 self.func = simplified_sum
1448
1449
1450class TestSum(NumericTestCase):
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001451 # Test cases for statistics._sum() function.
1452
Steven D'Apranob28c3272015-12-01 19:59:53 +11001453 # These tests look at the entire three value tuple returned by _sum.
1454
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001455 def setUp(self):
1456 self.func = statistics._sum
1457
1458 def test_empty_data(self):
1459 # Override test for empty data.
1460 for data in ([], (), iter([])):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001461 self.assertEqual(self.func(data), (int, Fraction(0), 0))
1462 self.assertEqual(self.func(data, 23), (int, Fraction(23), 0))
1463 self.assertEqual(self.func(data, 2.3), (float, Fraction(2.3), 0))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001464
1465 def test_ints(self):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001466 self.assertEqual(self.func([1, 5, 3, -4, -8, 20, 42, 1]),
1467 (int, Fraction(60), 8))
1468 self.assertEqual(self.func([4, 2, 3, -8, 7], 1000),
1469 (int, Fraction(1008), 5))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001470
1471 def test_floats(self):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001472 self.assertEqual(self.func([0.25]*20),
1473 (float, Fraction(5.0), 20))
1474 self.assertEqual(self.func([0.125, 0.25, 0.5, 0.75], 1.5),
1475 (float, Fraction(3.125), 4))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001476
1477 def test_fractions(self):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001478 self.assertEqual(self.func([Fraction(1, 1000)]*500),
1479 (Fraction, Fraction(1, 2), 500))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001480
1481 def test_decimals(self):
1482 D = Decimal
1483 data = [D("0.001"), D("5.246"), D("1.702"), D("-0.025"),
1484 D("3.974"), D("2.328"), D("4.617"), D("2.843"),
1485 ]
Steven D'Apranob28c3272015-12-01 19:59:53 +11001486 self.assertEqual(self.func(data),
1487 (Decimal, Decimal("20.686"), 8))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001488
1489 def test_compare_with_math_fsum(self):
1490 # Compare with the math.fsum function.
1491 # Ideally we ought to get the exact same result, but sometimes
1492 # we differ by a very slight amount :-(
1493 data = [random.uniform(-100, 1000) for _ in range(1000)]
Steven D'Apranob28c3272015-12-01 19:59:53 +11001494 self.assertApproxEqual(float(self.func(data)[1]), math.fsum(data), rel=2e-16)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001495
1496 def test_start_argument(self):
1497 # Test that the optional start argument works correctly.
1498 data = [random.uniform(1, 1000) for _ in range(100)]
Steven D'Apranob28c3272015-12-01 19:59:53 +11001499 t = self.func(data)[1]
1500 self.assertEqual(t+42, self.func(data, 42)[1])
1501 self.assertEqual(t-23, self.func(data, -23)[1])
1502 self.assertEqual(t+Fraction(1e20), self.func(data, 1e20)[1])
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001503
1504 def test_strings_fail(self):
1505 # Sum of strings should fail.
1506 self.assertRaises(TypeError, self.func, [1, 2, 3], '999')
1507 self.assertRaises(TypeError, self.func, [1, 2, 3, '999'])
1508
1509 def test_bytes_fail(self):
1510 # Sum of bytes should fail.
1511 self.assertRaises(TypeError, self.func, [1, 2, 3], b'999')
1512 self.assertRaises(TypeError, self.func, [1, 2, 3, b'999'])
1513
1514 def test_mixed_sum(self):
Nick Coghlan73afe2a2014-02-08 19:58:04 +10001515 # Mixed input types are not (currently) allowed.
1516 # Check that mixed data types fail.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001517 self.assertRaises(TypeError, self.func, [1, 2.0, Decimal(1)])
Nick Coghlan73afe2a2014-02-08 19:58:04 +10001518 # And so does mixed start argument.
1519 self.assertRaises(TypeError, self.func, [1, 2.0], Decimal(1))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001520
1521
1522class SumTortureTest(NumericTestCase):
1523 def test_torture(self):
1524 # Tim Peters' torture test for sum, and variants of same.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001525 self.assertEqual(statistics._sum([1, 1e100, 1, -1e100]*10000),
1526 (float, Fraction(20000.0), 40000))
1527 self.assertEqual(statistics._sum([1e100, 1, 1, -1e100]*10000),
1528 (float, Fraction(20000.0), 40000))
1529 T, num, count = statistics._sum([1e-100, 1, 1e-100, -1]*10000)
1530 self.assertIs(T, float)
1531 self.assertEqual(count, 40000)
1532 self.assertApproxEqual(float(num), 2.0e-96, rel=5e-16)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001533
1534
1535class SumSpecialValues(NumericTestCase):
1536 # Test that sum works correctly with IEEE-754 special values.
1537
1538 def test_nan(self):
1539 for type_ in (float, Decimal):
1540 nan = type_('nan')
Steven D'Apranob28c3272015-12-01 19:59:53 +11001541 result = statistics._sum([1, nan, 2])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001542 self.assertIs(type(result), type_)
1543 self.assertTrue(math.isnan(result))
1544
1545 def check_infinity(self, x, inf):
1546 """Check x is an infinity of the same type and sign as inf."""
1547 self.assertTrue(math.isinf(x))
1548 self.assertIs(type(x), type(inf))
1549 self.assertEqual(x > 0, inf > 0)
1550 assert x == inf
1551
1552 def do_test_inf(self, inf):
1553 # Adding a single infinity gives infinity.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001554 result = statistics._sum([1, 2, inf, 3])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001555 self.check_infinity(result, inf)
1556 # Adding two infinities of the same sign also gives infinity.
Steven D'Apranob28c3272015-12-01 19:59:53 +11001557 result = statistics._sum([1, 2, inf, 3, inf, 4])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001558 self.check_infinity(result, inf)
1559
1560 def test_float_inf(self):
1561 inf = float('inf')
1562 for sign in (+1, -1):
1563 self.do_test_inf(sign*inf)
1564
1565 def test_decimal_inf(self):
1566 inf = Decimal('inf')
1567 for sign in (+1, -1):
1568 self.do_test_inf(sign*inf)
1569
1570 def test_float_mismatched_infs(self):
1571 # Test that adding two infinities of opposite sign gives a NAN.
1572 inf = float('inf')
Steven D'Apranob28c3272015-12-01 19:59:53 +11001573 result = statistics._sum([1, 2, inf, 3, -inf, 4])[1]
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001574 self.assertTrue(math.isnan(result))
1575
Berker Peksagf8c111d2014-09-24 15:03:25 +03001576 def test_decimal_extendedcontext_mismatched_infs_to_nan(self):
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001577 # Test adding Decimal INFs with opposite sign returns NAN.
1578 inf = Decimal('inf')
1579 data = [1, 2, inf, 3, -inf, 4]
1580 with decimal.localcontext(decimal.ExtendedContext):
Steven D'Apranob28c3272015-12-01 19:59:53 +11001581 self.assertTrue(math.isnan(statistics._sum(data)[1]))
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001582
Berker Peksagf8c111d2014-09-24 15:03:25 +03001583 def test_decimal_basiccontext_mismatched_infs_to_nan(self):
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001584 # Test adding Decimal INFs with opposite sign raises InvalidOperation.
1585 inf = Decimal('inf')
1586 data = [1, 2, inf, 3, -inf, 4]
1587 with decimal.localcontext(decimal.BasicContext):
1588 self.assertRaises(decimal.InvalidOperation, statistics._sum, data)
1589
1590 def test_decimal_snan_raises(self):
1591 # Adding sNAN should raise InvalidOperation.
1592 sNAN = Decimal('sNAN')
1593 data = [1, sNAN, 2]
1594 self.assertRaises(decimal.InvalidOperation, statistics._sum, data)
1595
1596
1597# === Tests for averages ===
1598
1599class AverageMixin(UnivariateCommonMixin):
1600 # Mixin class holding common tests for averages.
1601
1602 def test_single_value(self):
1603 # Average of a single value is the value itself.
1604 for x in (23, 42.5, 1.3e15, Fraction(15, 19), Decimal('0.28')):
1605 self.assertEqual(self.func([x]), x)
1606
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001607 def prepare_values_for_repeated_single_test(self):
1608 return (3.5, 17, 2.5e15, Fraction(61, 67), Decimal('4.9712'))
1609
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001610 def test_repeated_single_value(self):
1611 # The average of a single repeated value is the value itself.
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001612 for x in self.prepare_values_for_repeated_single_test():
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001613 for count in (2, 5, 10, 20):
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001614 with self.subTest(x=x, count=count):
1615 data = [x]*count
1616 self.assertEqual(self.func(data), x)
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001617
1618
1619class TestMean(NumericTestCase, AverageMixin, UnivariateTypeMixin):
1620 def setUp(self):
1621 self.func = statistics.mean
1622
1623 def test_torture_pep(self):
1624 # "Torture Test" from PEP-450.
1625 self.assertEqual(self.func([1e100, 1, 3, -1e100]), 1)
1626
1627 def test_ints(self):
1628 # Test mean with ints.
1629 data = [0, 1, 2, 3, 3, 3, 4, 5, 5, 6, 7, 7, 7, 7, 8, 9]
1630 random.shuffle(data)
1631 self.assertEqual(self.func(data), 4.8125)
1632
1633 def test_floats(self):
1634 # Test mean with floats.
1635 data = [17.25, 19.75, 20.0, 21.5, 21.75, 23.25, 25.125, 27.5]
1636 random.shuffle(data)
1637 self.assertEqual(self.func(data), 22.015625)
1638
1639 def test_decimals(self):
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001640 # Test mean with Decimals.
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001641 D = Decimal
1642 data = [D("1.634"), D("2.517"), D("3.912"), D("4.072"), D("5.813")]
1643 random.shuffle(data)
1644 self.assertEqual(self.func(data), D("3.5896"))
1645
1646 def test_fractions(self):
1647 # Test mean with Fractions.
1648 F = Fraction
1649 data = [F(1, 2), F(2, 3), F(3, 4), F(4, 5), F(5, 6), F(6, 7), F(7, 8)]
1650 random.shuffle(data)
1651 self.assertEqual(self.func(data), F(1479, 1960))
1652
1653 def test_inf(self):
1654 # Test mean with infinities.
1655 raw = [1, 3, 5, 7, 9] # Use only ints, to avoid TypeError later.
1656 for kind in (float, Decimal):
1657 for sign in (1, -1):
1658 inf = kind("inf")*sign
1659 data = raw + [inf]
1660 result = self.func(data)
1661 self.assertTrue(math.isinf(result))
1662 self.assertEqual(result, inf)
1663
1664 def test_mismatched_infs(self):
1665 # Test mean with infinities of opposite sign.
1666 data = [2, 4, 6, float('inf'), 1, 3, 5, float('-inf')]
1667 result = self.func(data)
1668 self.assertTrue(math.isnan(result))
1669
1670 def test_nan(self):
1671 # Test mean with NANs.
1672 raw = [1, 3, 5, 7, 9] # Use only ints, to avoid TypeError later.
1673 for kind in (float, Decimal):
1674 inf = kind("nan")
1675 data = raw + [inf]
1676 result = self.func(data)
1677 self.assertTrue(math.isnan(result))
1678
1679 def test_big_data(self):
1680 # Test adding a large constant to every data point.
1681 c = 1e9
1682 data = [3.4, 4.5, 4.9, 6.7, 6.8, 7.2, 8.0, 8.1, 9.4]
1683 expected = self.func(data) + c
1684 assert expected != c
1685 result = self.func([x+c for x in data])
1686 self.assertEqual(result, expected)
1687
1688 def test_doubled_data(self):
1689 # Mean of [a,b,c...z] should be same as for [a,a,b,b,c,c...z,z].
1690 data = [random.uniform(-3, 5) for _ in range(1000)]
1691 expected = self.func(data)
1692 actual = self.func(data*2)
1693 self.assertApproxEqual(actual, expected)
1694
Nick Coghlan4a7668a2014-02-08 23:55:14 +10001695 def test_regression_20561(self):
1696 # Regression test for issue 20561.
1697 # See http://bugs.python.org/issue20561
1698 d = Decimal('1e4')
1699 self.assertEqual(statistics.mean([d]), d)
1700
Steven D'Apranob28c3272015-12-01 19:59:53 +11001701 def test_regression_25177(self):
1702 # Regression test for issue 25177.
1703 # Ensure very big and very small floats don't overflow.
1704 # See http://bugs.python.org/issue25177.
1705 self.assertEqual(statistics.mean(
1706 [8.988465674311579e+307, 8.98846567431158e+307]),
1707 8.98846567431158e+307)
1708 big = 8.98846567431158e+307
1709 tiny = 5e-324
1710 for n in (2, 3, 5, 200):
1711 self.assertEqual(statistics.mean([big]*n), big)
1712 self.assertEqual(statistics.mean([tiny]*n), tiny)
1713
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001714
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001715class TestHarmonicMean(NumericTestCase, AverageMixin, UnivariateTypeMixin):
1716 def setUp(self):
1717 self.func = statistics.harmonic_mean
1718
1719 def prepare_data(self):
1720 # Override mixin method.
1721 values = super().prepare_data()
1722 values.remove(0)
1723 return values
1724
1725 def prepare_values_for_repeated_single_test(self):
1726 # Override mixin method.
1727 return (3.5, 17, 2.5e15, Fraction(61, 67), Decimal('4.125'))
1728
1729 def test_zero(self):
1730 # Test that harmonic mean returns zero when given zero.
1731 values = [1, 0, 2]
1732 self.assertEqual(self.func(values), 0)
1733
1734 def test_negative_error(self):
1735 # Test that harmonic mean raises when given a negative value.
1736 exc = statistics.StatisticsError
1737 for values in ([-1], [1, -2, 3]):
1738 with self.subTest(values=values):
1739 self.assertRaises(exc, self.func, values)
1740
1741 def test_ints(self):
1742 # Test harmonic mean with ints.
1743 data = [2, 4, 4, 8, 16, 16]
1744 random.shuffle(data)
1745 self.assertEqual(self.func(data), 6*4/5)
1746
1747 def test_floats_exact(self):
1748 # Test harmonic mean with some carefully chosen floats.
1749 data = [1/8, 1/4, 1/4, 1/2, 1/2]
1750 random.shuffle(data)
1751 self.assertEqual(self.func(data), 1/4)
1752 self.assertEqual(self.func([0.25, 0.5, 1.0, 1.0]), 0.5)
1753
1754 def test_singleton_lists(self):
1755 # Test that harmonic mean([x]) returns (approximately) x.
1756 for x in range(1, 101):
Steven D'Apranoe7fef522016-08-09 13:19:48 +10001757 self.assertEqual(self.func([x]), x)
Steven D'Apranoa474afd2016-08-09 12:49:01 +10001758
1759 def test_decimals_exact(self):
1760 # Test harmonic mean with some carefully chosen Decimals.
1761 D = Decimal
1762 self.assertEqual(self.func([D(15), D(30), D(60), D(60)]), D(30))
1763 data = [D("0.05"), D("0.10"), D("0.20"), D("0.20")]
1764 random.shuffle(data)
1765 self.assertEqual(self.func(data), D("0.10"))
1766 data = [D("1.68"), D("0.32"), D("5.94"), D("2.75")]
1767 random.shuffle(data)
1768 self.assertEqual(self.func(data), D(66528)/70723)
1769
1770 def test_fractions(self):
1771 # Test harmonic mean with Fractions.
1772 F = Fraction
1773 data = [F(1, 2), F(2, 3), F(3, 4), F(4, 5), F(5, 6), F(6, 7), F(7, 8)]
1774 random.shuffle(data)
1775 self.assertEqual(self.func(data), F(7*420, 4029))
1776
1777 def test_inf(self):
1778 # Test harmonic mean with infinity.
1779 values = [2.0, float('inf'), 1.0]
1780 self.assertEqual(self.func(values), 2.0)
1781
1782 def test_nan(self):
1783 # Test harmonic mean with NANs.
1784 values = [2.0, float('nan'), 1.0]
1785 self.assertTrue(math.isnan(self.func(values)))
1786
1787 def test_multiply_data_points(self):
1788 # Test multiplying every data point by a constant.
1789 c = 111
1790 data = [3.4, 4.5, 4.9, 6.7, 6.8, 7.2, 8.0, 8.1, 9.4]
1791 expected = self.func(data)*c
1792 result = self.func([x*c for x in data])
1793 self.assertEqual(result, expected)
1794
1795 def test_doubled_data(self):
1796 # Harmonic mean of [a,b...z] should be same as for [a,a,b,b...z,z].
1797 data = [random.uniform(1, 5) for _ in range(1000)]
1798 expected = self.func(data)
1799 actual = self.func(data*2)
1800 self.assertApproxEqual(actual, expected)
1801
1802
Larry Hastingsf5e987b2013-10-19 11:50:09 -07001803class TestMedian(NumericTestCase, AverageMixin):
1804 # Common tests for median and all median.* functions.
1805 def setUp(self):
1806 self.func = statistics.median
1807
1808 def prepare_data(self):
1809 """Overload method from UnivariateCommonMixin."""
1810 data = super().prepare_data()
1811 if len(data)%2 != 1:
1812 data.append(2)
1813 return data
1814
1815 def test_even_ints(self):
1816 # Test median with an even number of int data points.
1817 data = [1, 2, 3, 4, 5, 6]
1818 assert len(data)%2 == 0
1819 self.assertEqual(self.func(data), 3.5)
1820
1821 def test_odd_ints(self):
1822 # Test median with an odd number of int data points.
1823 data = [1, 2, 3, 4, 5, 6, 9]
1824 assert len(data)%2 == 1
1825 self.assertEqual(self.func(data), 4)
1826
1827 def test_odd_fractions(self):
1828 # Test median works with an odd number of Fractions.
1829 F = Fraction
1830 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7)]
1831 assert len(data)%2 == 1
1832 random.shuffle(data)
1833 self.assertEqual(self.func(data), F(3, 7))
1834
1835 def test_even_fractions(self):
1836 # Test median works with an even number of Fractions.
1837 F = Fraction
1838 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7), F(6, 7)]
1839 assert len(data)%2 == 0
1840 random.shuffle(data)
1841 self.assertEqual(self.func(data), F(1, 2))
1842
1843 def test_odd_decimals(self):
1844 # Test median works with an odd number of Decimals.
1845 D = Decimal
1846 data = [D('2.5'), D('3.1'), D('4.2'), D('5.7'), D('5.8')]
1847 assert len(data)%2 == 1
1848 random.shuffle(data)
1849 self.assertEqual(self.func(data), D('4.2'))
1850
1851 def test_even_decimals(self):
1852 # Test median works with an even number of Decimals.
1853 D = Decimal
1854 data = [D('1.2'), D('2.5'), D('3.1'), D('4.2'), D('5.7'), D('5.8')]
1855 assert len(data)%2 == 0
1856 random.shuffle(data)
1857 self.assertEqual(self.func(data), D('3.65'))
1858
1859
1860class TestMedianDataType(NumericTestCase, UnivariateTypeMixin):
1861 # Test conservation of data element type for median.
1862 def setUp(self):
1863 self.func = statistics.median
1864
1865 def prepare_data(self):
1866 data = list(range(15))
1867 assert len(data)%2 == 1
1868 while data == sorted(data):
1869 random.shuffle(data)
1870 return data
1871
1872
1873class TestMedianLow(TestMedian, UnivariateTypeMixin):
1874 def setUp(self):
1875 self.func = statistics.median_low
1876
1877 def test_even_ints(self):
1878 # Test median_low with an even number of ints.
1879 data = [1, 2, 3, 4, 5, 6]
1880 assert len(data)%2 == 0
1881 self.assertEqual(self.func(data), 3)
1882
1883 def test_even_fractions(self):
1884 # Test median_low works with an even number of Fractions.
1885 F = Fraction
1886 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7), F(6, 7)]
1887 assert len(data)%2 == 0
1888 random.shuffle(data)
1889 self.assertEqual(self.func(data), F(3, 7))
1890
1891 def test_even_decimals(self):
1892 # Test median_low works with an even number of Decimals.
1893 D = Decimal
1894 data = [D('1.1'), D('2.2'), D('3.3'), D('4.4'), D('5.5'), D('6.6')]
1895 assert len(data)%2 == 0
1896 random.shuffle(data)
1897 self.assertEqual(self.func(data), D('3.3'))
1898
1899
1900class TestMedianHigh(TestMedian, UnivariateTypeMixin):
1901 def setUp(self):
1902 self.func = statistics.median_high
1903
1904 def test_even_ints(self):
1905 # Test median_high with an even number of ints.
1906 data = [1, 2, 3, 4, 5, 6]
1907 assert len(data)%2 == 0
1908 self.assertEqual(self.func(data), 4)
1909
1910 def test_even_fractions(self):
1911 # Test median_high works with an even number of Fractions.
1912 F = Fraction
1913 data = [F(1, 7), F(2, 7), F(3, 7), F(4, 7), F(5, 7), F(6, 7)]
1914 assert len(data)%2 == 0
1915 random.shuffle(data)
1916 self.assertEqual(self.func(data), F(4, 7))
1917
1918 def test_even_decimals(self):
1919 # Test median_high works with an even number of Decimals.
1920 D = Decimal
1921 data = [D('1.1'), D('2.2'), D('3.3'), D('4.4'), D('5.5'), D('6.6')]
1922 assert len(data)%2 == 0
1923 random.shuffle(data)
1924 self.assertEqual(self.func(data), D('4.4'))
1925
1926
1927class TestMedianGrouped(TestMedian):
1928 # Test median_grouped.
1929 # Doesn't conserve data element types, so don't use TestMedianType.
1930 def setUp(self):
1931 self.func = statistics.median_grouped
1932
1933 def test_odd_number_repeated(self):
1934 # Test median.grouped with repeated median values.
1935 data = [12, 13, 14, 14, 14, 15, 15]
1936 assert len(data)%2 == 1
1937 self.assertEqual(self.func(data), 14)
1938 #---
1939 data = [12, 13, 14, 14, 14, 14, 15]
1940 assert len(data)%2 == 1
1941 self.assertEqual(self.func(data), 13.875)
1942 #---
1943 data = [5, 10, 10, 15, 20, 20, 20, 20, 25, 25, 30]
1944 assert len(data)%2 == 1
1945 self.assertEqual(self.func(data, 5), 19.375)
1946 #---
1947 data = [16, 18, 18, 18, 18, 20, 20, 20, 22, 22, 22, 24, 24, 26, 28]
1948 assert len(data)%2 == 1
1949 self.assertApproxEqual(self.func(data, 2), 20.66666667, tol=1e-8)
1950
1951 def test_even_number_repeated(self):
1952 # Test median.grouped with repeated median values.
1953 data = [5, 10, 10, 15, 20, 20, 20, 25, 25, 30]
1954 assert len(data)%2 == 0
1955 self.assertApproxEqual(self.func(data, 5), 19.16666667, tol=1e-8)
1956 #---
1957 data = [2, 3, 4, 4, 4, 5]
1958 assert len(data)%2 == 0
1959 self.assertApproxEqual(self.func(data), 3.83333333, tol=1e-8)
1960 #---
1961 data = [2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6]
1962 assert len(data)%2 == 0
1963 self.assertEqual(self.func(data), 4.5)
1964 #---
1965 data = [3, 4, 4, 4, 5, 5, 5, 5, 6, 6]
1966 assert len(data)%2 == 0
1967 self.assertEqual(self.func(data), 4.75)
1968
1969 def test_repeated_single_value(self):
1970 # Override method from AverageMixin.
1971 # Yet again, failure of median_grouped to conserve the data type
1972 # causes me headaches :-(
1973 for x in (5.3, 68, 4.3e17, Fraction(29, 101), Decimal('32.9714')):
1974 for count in (2, 5, 10, 20):
1975 data = [x]*count
1976 self.assertEqual(self.func(data), float(x))
1977
1978 def test_odd_fractions(self):
1979 # Test median_grouped works with an odd number of Fractions.
1980 F = Fraction
1981 data = [F(5, 4), F(9, 4), F(13, 4), F(13, 4), F(17, 4)]
1982 assert len(data)%2 == 1
1983 random.shuffle(data)
1984 self.assertEqual(self.func(data), 3.0)
1985
1986 def test_even_fractions(self):
1987 # Test median_grouped works with an even number of Fractions.
1988 F = Fraction
1989 data = [F(5, 4), F(9, 4), F(13, 4), F(13, 4), F(17, 4), F(17, 4)]
1990 assert len(data)%2 == 0
1991 random.shuffle(data)
1992 self.assertEqual(self.func(data), 3.25)
1993
1994 def test_odd_decimals(self):
1995 # Test median_grouped works with an odd number of Decimals.
1996 D = Decimal
1997 data = [D('5.5'), D('6.5'), D('6.5'), D('7.5'), D('8.5')]
1998 assert len(data)%2 == 1
1999 random.shuffle(data)
2000 self.assertEqual(self.func(data), 6.75)
2001
2002 def test_even_decimals(self):
2003 # Test median_grouped works with an even number of Decimals.
2004 D = Decimal
2005 data = [D('5.5'), D('5.5'), D('6.5'), D('6.5'), D('7.5'), D('8.5')]
2006 assert len(data)%2 == 0
2007 random.shuffle(data)
2008 self.assertEqual(self.func(data), 6.5)
2009 #---
2010 data = [D('5.5'), D('5.5'), D('6.5'), D('7.5'), D('7.5'), D('8.5')]
2011 assert len(data)%2 == 0
2012 random.shuffle(data)
2013 self.assertEqual(self.func(data), 7.0)
2014
2015 def test_interval(self):
2016 # Test median_grouped with interval argument.
2017 data = [2.25, 2.5, 2.5, 2.75, 2.75, 3.0, 3.0, 3.25, 3.5, 3.75]
2018 self.assertEqual(self.func(data, 0.25), 2.875)
2019 data = [2.25, 2.5, 2.5, 2.75, 2.75, 2.75, 3.0, 3.0, 3.25, 3.5, 3.75]
2020 self.assertApproxEqual(self.func(data, 0.25), 2.83333333, tol=1e-8)
2021 data = [220, 220, 240, 260, 260, 260, 260, 280, 280, 300, 320, 340]
2022 self.assertEqual(self.func(data, 20), 265.0)
2023
Steven D'Aprano8c115a42016-07-08 02:38:45 +10002024 def test_data_type_error(self):
2025 # Test median_grouped with str, bytes data types for data and interval
2026 data = ["", "", ""]
2027 self.assertRaises(TypeError, self.func, data)
2028 #---
2029 data = [b"", b"", b""]
2030 self.assertRaises(TypeError, self.func, data)
2031 #---
2032 data = [1, 2, 3]
2033 interval = ""
2034 self.assertRaises(TypeError, self.func, data, interval)
2035 #---
2036 data = [1, 2, 3]
2037 interval = b""
2038 self.assertRaises(TypeError, self.func, data, interval)
2039
Larry Hastingsf5e987b2013-10-19 11:50:09 -07002040
2041class TestMode(NumericTestCase, AverageMixin, UnivariateTypeMixin):
2042 # Test cases for the discrete version of mode.
2043 def setUp(self):
2044 self.func = statistics.mode
2045
2046 def prepare_data(self):
2047 """Overload method from UnivariateCommonMixin."""
2048 # Make sure test data has exactly one mode.
2049 return [1, 1, 1, 1, 3, 4, 7, 9, 0, 8, 2]
2050
2051 def test_range_data(self):
2052 # Override test from UnivariateCommonMixin.
2053 data = range(20, 50, 3)
2054 self.assertRaises(statistics.StatisticsError, self.func, data)
2055
2056 def test_nominal_data(self):
2057 # Test mode with nominal data.
2058 data = 'abcbdb'
2059 self.assertEqual(self.func(data), 'b')
2060 data = 'fe fi fo fum fi fi'.split()
2061 self.assertEqual(self.func(data), 'fi')
2062
2063 def test_discrete_data(self):
2064 # Test mode with discrete numeric data.
2065 data = list(range(10))
2066 for i in range(10):
2067 d = data + [i]
2068 random.shuffle(d)
2069 self.assertEqual(self.func(d), i)
2070
2071 def test_bimodal_data(self):
2072 # Test mode with bimodal data.
2073 data = [1, 1, 2, 2, 2, 2, 3, 4, 5, 6, 6, 6, 6, 7, 8, 9, 9]
2074 assert data.count(2) == data.count(6) == 4
2075 # Check for an exception.
2076 self.assertRaises(statistics.StatisticsError, self.func, data)
2077
2078 def test_unique_data_failure(self):
2079 # Test mode exception when data points are all unique.
2080 data = list(range(10))
2081 self.assertRaises(statistics.StatisticsError, self.func, data)
2082
2083 def test_none_data(self):
2084 # Test that mode raises TypeError if given None as data.
2085
2086 # This test is necessary because the implementation of mode uses
2087 # collections.Counter, which accepts None and returns an empty dict.
2088 self.assertRaises(TypeError, self.func, None)
2089
Nick Coghlanbfd68bf2014-02-08 19:44:16 +10002090 def test_counter_data(self):
2091 # Test that a Counter is treated like any other iterable.
2092 data = collections.Counter([1, 1, 1, 2])
2093 # Since the keys of the counter are treated as data points, not the
2094 # counts, this should raise.
2095 self.assertRaises(statistics.StatisticsError, self.func, data)
2096
2097
Larry Hastingsf5e987b2013-10-19 11:50:09 -07002098
2099# === Tests for variances and standard deviations ===
2100
2101class VarianceStdevMixin(UnivariateCommonMixin):
2102 # Mixin class holding common tests for variance and std dev.
2103
2104 # Subclasses should inherit from this before NumericTestClass, in order
2105 # to see the rel attribute below. See testShiftData for an explanation.
2106
2107 rel = 1e-12
2108
2109 def test_single_value(self):
2110 # Deviation of a single value is zero.
2111 for x in (11, 19.8, 4.6e14, Fraction(21, 34), Decimal('8.392')):
2112 self.assertEqual(self.func([x]), 0)
2113
2114 def test_repeated_single_value(self):
2115 # The deviation of a single repeated value is zero.
2116 for x in (7.2, 49, 8.1e15, Fraction(3, 7), Decimal('62.4802')):
2117 for count in (2, 3, 5, 15):
2118 data = [x]*count
2119 self.assertEqual(self.func(data), 0)
2120
2121 def test_domain_error_regression(self):
2122 # Regression test for a domain error exception.
2123 # (Thanks to Geremy Condra.)
2124 data = [0.123456789012345]*10000
2125 # All the items are identical, so variance should be exactly zero.
2126 # We allow some small round-off error, but not much.
2127 result = self.func(data)
2128 self.assertApproxEqual(result, 0.0, tol=5e-17)
2129 self.assertGreaterEqual(result, 0) # A negative result must fail.
2130
2131 def test_shift_data(self):
2132 # Test that shifting the data by a constant amount does not affect
2133 # the variance or stdev. Or at least not much.
2134
2135 # Due to rounding, this test should be considered an ideal. We allow
2136 # some tolerance away from "no change at all" by setting tol and/or rel
2137 # attributes. Subclasses may set tighter or looser error tolerances.
2138 raw = [1.03, 1.27, 1.94, 2.04, 2.58, 3.14, 4.75, 4.98, 5.42, 6.78]
2139 expected = self.func(raw)
2140 # Don't set shift too high, the bigger it is, the more rounding error.
2141 shift = 1e5
2142 data = [x + shift for x in raw]
2143 self.assertApproxEqual(self.func(data), expected)
2144
2145 def test_shift_data_exact(self):
2146 # Like test_shift_data, but result is always exact.
2147 raw = [1, 3, 3, 4, 5, 7, 9, 10, 11, 16]
2148 assert all(x==int(x) for x in raw)
2149 expected = self.func(raw)
2150 shift = 10**9
2151 data = [x + shift for x in raw]
2152 self.assertEqual(self.func(data), expected)
2153
2154 def test_iter_list_same(self):
2155 # Test that iter data and list data give the same result.
2156
2157 # This is an explicit test that iterators and lists are treated the
2158 # same; justification for this test over and above the similar test
2159 # in UnivariateCommonMixin is that an earlier design had variance and
2160 # friends swap between one- and two-pass algorithms, which would
2161 # sometimes give different results.
2162 data = [random.uniform(-3, 8) for _ in range(1000)]
2163 expected = self.func(data)
2164 self.assertEqual(self.func(iter(data)), expected)
2165
2166
2167class TestPVariance(VarianceStdevMixin, NumericTestCase, UnivariateTypeMixin):
2168 # Tests for population variance.
2169 def setUp(self):
2170 self.func = statistics.pvariance
2171
2172 def test_exact_uniform(self):
2173 # Test the variance against an exact result for uniform data.
2174 data = list(range(10000))
2175 random.shuffle(data)
2176 expected = (10000**2 - 1)/12 # Exact value.
2177 self.assertEqual(self.func(data), expected)
2178
2179 def test_ints(self):
2180 # Test population variance with int data.
2181 data = [4, 7, 13, 16]
2182 exact = 22.5
2183 self.assertEqual(self.func(data), exact)
2184
2185 def test_fractions(self):
2186 # Test population variance with Fraction data.
2187 F = Fraction
2188 data = [F(1, 4), F(1, 4), F(3, 4), F(7, 4)]
2189 exact = F(3, 8)
2190 result = self.func(data)
2191 self.assertEqual(result, exact)
2192 self.assertIsInstance(result, Fraction)
2193
2194 def test_decimals(self):
2195 # Test population variance with Decimal data.
2196 D = Decimal
2197 data = [D("12.1"), D("12.2"), D("12.5"), D("12.9")]
2198 exact = D('0.096875')
2199 result = self.func(data)
2200 self.assertEqual(result, exact)
2201 self.assertIsInstance(result, Decimal)
2202
2203
2204class TestVariance(VarianceStdevMixin, NumericTestCase, UnivariateTypeMixin):
2205 # Tests for sample variance.
2206 def setUp(self):
2207 self.func = statistics.variance
2208
2209 def test_single_value(self):
2210 # Override method from VarianceStdevMixin.
2211 for x in (35, 24.7, 8.2e15, Fraction(19, 30), Decimal('4.2084')):
2212 self.assertRaises(statistics.StatisticsError, self.func, [x])
2213
2214 def test_ints(self):
2215 # Test sample variance with int data.
2216 data = [4, 7, 13, 16]
2217 exact = 30
2218 self.assertEqual(self.func(data), exact)
2219
2220 def test_fractions(self):
2221 # Test sample variance with Fraction data.
2222 F = Fraction
2223 data = [F(1, 4), F(1, 4), F(3, 4), F(7, 4)]
2224 exact = F(1, 2)
2225 result = self.func(data)
2226 self.assertEqual(result, exact)
2227 self.assertIsInstance(result, Fraction)
2228
2229 def test_decimals(self):
2230 # Test sample variance with Decimal data.
2231 D = Decimal
2232 data = [D(2), D(2), D(7), D(9)]
2233 exact = 4*D('9.5')/D(3)
2234 result = self.func(data)
2235 self.assertEqual(result, exact)
2236 self.assertIsInstance(result, Decimal)
2237
2238
2239class TestPStdev(VarianceStdevMixin, NumericTestCase):
2240 # Tests for population standard deviation.
2241 def setUp(self):
2242 self.func = statistics.pstdev
2243
2244 def test_compare_to_variance(self):
2245 # Test that stdev is, in fact, the square root of variance.
2246 data = [random.uniform(-17, 24) for _ in range(1000)]
2247 expected = math.sqrt(statistics.pvariance(data))
2248 self.assertEqual(self.func(data), expected)
2249
2250
2251class TestStdev(VarianceStdevMixin, NumericTestCase):
2252 # Tests for sample standard deviation.
2253 def setUp(self):
2254 self.func = statistics.stdev
2255
2256 def test_single_value(self):
2257 # Override method from VarianceStdevMixin.
2258 for x in (81, 203.74, 3.9e14, Fraction(5, 21), Decimal('35.719')):
2259 self.assertRaises(statistics.StatisticsError, self.func, [x])
2260
2261 def test_compare_to_variance(self):
2262 # Test that stdev is, in fact, the square root of variance.
2263 data = [random.uniform(-2, 9) for _ in range(1000)]
2264 expected = math.sqrt(statistics.variance(data))
2265 self.assertEqual(self.func(data), expected)
2266
2267
2268# === Run tests ===
2269
2270def load_tests(loader, tests, ignore):
2271 """Used for doctest/unittest integration."""
2272 tests.addTests(doctest.DocTestSuite())
2273 return tests
2274
2275
2276if __name__ == "__main__":
2277 unittest.main()