@@ -2038,6 +2038,94 @@ def test_compare_to_variance(self):
20382038 expected = math .sqrt (statistics .variance (data ))
20392039 self .assertEqual (self .func (data ), expected )
20402040
2041+ class TestGeometricMean (unittest .TestCase ):
2042+
2043+ def test_basics (self ):
2044+ geometric_mean = statistics .geometric_mean
2045+ self .assertAlmostEqual (geometric_mean ([54 , 24 , 36 ]), 36.0 )
2046+ self .assertAlmostEqual (geometric_mean ([4.0 , 9.0 ]), 6.0 )
2047+ self .assertAlmostEqual (geometric_mean ([17.625 ]), 17.625 )
2048+
2049+ random .seed (86753095551212 )
2050+ for rng in [
2051+ range (1 , 100 ),
2052+ range (1 , 1_000 ),
2053+ range (1 , 10_000 ),
2054+ range (500 , 10_000 , 3 ),
2055+ range (10_000 , 500 , - 3 ),
2056+ [12 , 17 , 13 , 5 , 120 , 7 ],
2057+ [random .expovariate (50.0 ) for i in range (1_000 )],
2058+ [random .lognormvariate (20.0 , 3.0 ) for i in range (2_000 )],
2059+ [random .triangular (2000 , 3000 , 2200 ) for i in range (3_000 )],
2060+ ]:
2061+ gm_decimal = math .prod (map (Decimal , rng )) ** (Decimal (1 ) / len (rng ))
2062+ gm_float = geometric_mean (rng )
2063+ self .assertTrue (math .isclose (gm_float , float (gm_decimal )))
2064+
2065+ def test_various_input_types (self ):
2066+ geometric_mean = statistics .geometric_mean
2067+ D = Decimal
2068+ F = Fraction
2069+ # https://www.wolframalpha.com/input/?i=geometric+mean+3.5,+4.0,+5.25
2070+ expected_mean = 4.18886
2071+ for data , kind in [
2072+ ([3.5 , 4.0 , 5.25 ], 'floats' ),
2073+ ([D ('3.5' ), D ('4.0' ), D ('5.25' )], 'decimals' ),
2074+ ([F (7 , 2 ), F (4 , 1 ), F (21 , 4 )], 'fractions' ),
2075+ ([3.5 , 4 , F (21 , 4 )], 'mixed types' ),
2076+ ((3.5 , 4.0 , 5.25 ), 'tuple' ),
2077+ (iter ([3.5 , 4.0 , 5.25 ]), 'iterator' ),
2078+ ]:
2079+ actual_mean = geometric_mean (data )
2080+ self .assertIs (type (actual_mean ), float , kind )
2081+ self .assertAlmostEqual (actual_mean , expected_mean , places = 5 )
2082+
2083+ def test_big_and_small (self ):
2084+ geometric_mean = statistics .geometric_mean
2085+
2086+ # Avoid overflow to infinity
2087+ large = 2.0 ** 1000
2088+ big_gm = geometric_mean ([54.0 * large , 24.0 * large , 36.0 * large ])
2089+ self .assertTrue (math .isclose (big_gm , 36.0 * large ))
2090+ self .assertFalse (math .isinf (big_gm ))
2091+
2092+ # Avoid underflow to zero
2093+ small = 2.0 ** - 1000
2094+ small_gm = geometric_mean ([54.0 * small , 24.0 * small , 36.0 * small ])
2095+ self .assertTrue (math .isclose (small_gm , 36.0 * small ))
2096+ self .assertNotEqual (small_gm , 0.0 )
2097+
2098+ def test_error_cases (self ):
2099+ geometric_mean = statistics .geometric_mean
2100+ StatisticsError = statistics .StatisticsError
2101+ with self .assertRaises (StatisticsError ):
2102+ geometric_mean ([]) # empty input
2103+ with self .assertRaises (StatisticsError ):
2104+ geometric_mean ([3.5 , 0.0 , 5.25 ]) # zero input
2105+ with self .assertRaises (StatisticsError ):
2106+ geometric_mean ([3.5 , - 4.0 , 5.25 ]) # negative input
2107+ with self .assertRaises (StatisticsError ):
2108+ geometric_mean (iter ([])) # empty iterator
2109+ with self .assertRaises (TypeError ):
2110+ geometric_mean (None ) # non-iterable input
2111+ with self .assertRaises (TypeError ):
2112+ geometric_mean ([10 , None , 20 ]) # non-numeric input
2113+ with self .assertRaises (TypeError ):
2114+ geometric_mean () # missing data argument
2115+ with self .assertRaises (TypeError ):
2116+ geometric_mean ([10 , 20 , 60 ], 70 ) # too many arguments
2117+
2118+ def test_special_values (self ):
2119+ # Rules for special values are inherited from math.fsum()
2120+ geometric_mean = statistics .geometric_mean
2121+ NaN = float ('Nan' )
2122+ Inf = float ('Inf' )
2123+ self .assertTrue (math .isnan (geometric_mean ([10 , NaN ])), 'nan' )
2124+ self .assertTrue (math .isnan (geometric_mean ([NaN , Inf ])), 'nan and infinity' )
2125+ self .assertTrue (math .isinf (geometric_mean ([10 , Inf ])), 'infinity' )
2126+ with self .assertRaises (ValueError ):
2127+ geometric_mean ([Inf , - Inf ])
2128+
20412129class TestNormalDist (unittest .TestCase ):
20422130
20432131 # General note on precision: The pdf(), cdf(), and overlap() methods
0 commit comments