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