@@ -2040,6 +2040,13 @@ def test_compare_to_variance(self):
20402040
20412041class TestNormalDist (unittest .TestCase ):
20422042
2043+ # General note on precision: The pdf(), cdf(), and overlap() methods
2044+ # depend on functions in the math libraries that do not make
2045+ # explicit accuracy guarantees. Accordingly, some of the accuracy
2046+ # tests below may fail if the underlying math functions are
2047+ # inaccurate. There isn't much we can do about this short of
2048+ # implementing our own implementations from scratch.
2049+
20432050 def test_slots (self ):
20442051 nd = statistics .NormalDist (300 , 23 )
20452052 with self .assertRaises (TypeError ):
@@ -2062,6 +2069,12 @@ def test_instantiation_and_attributes(self):
20622069 with self .assertRaises (statistics .StatisticsError ):
20632070 statistics .NormalDist (500 , - 10 )
20642071
2072+ # verify that subclass type is honored
2073+ class NewNormalDist (statistics .NormalDist ):
2074+ pass
2075+ nnd = NewNormalDist (200 , 5 )
2076+ self .assertEqual (type (nnd ), NewNormalDist )
2077+
20652078 def test_alternative_constructor (self ):
20662079 NormalDist = statistics .NormalDist
20672080 data = [96 , 107 , 90 , 92 , 110 ]
@@ -2077,6 +2090,12 @@ def test_alternative_constructor(self):
20772090 with self .assertRaises (statistics .StatisticsError ):
20782091 NormalDist .from_samples ([10 ]) # only one input
20792092
2093+ # verify that subclass type is honored
2094+ class NewNormalDist (NormalDist ):
2095+ pass
2096+ nnd = NewNormalDist .from_samples (data )
2097+ self .assertEqual (type (nnd ), NewNormalDist )
2098+
20802099 def test_sample_generation (self ):
20812100 NormalDist = statistics .NormalDist
20822101 mu , sigma = 10_000 , 3.0
@@ -2099,12 +2118,6 @@ def test_sample_generation(self):
20992118 self .assertEqual (data2 , data4 )
21002119 self .assertNotEqual (data1 , data2 )
21012120
2102- # verify that subclass type is honored
2103- class NewNormalDist (NormalDist ):
2104- pass
2105- nnd = NewNormalDist (200 , 5 )
2106- self .assertEqual (type (nnd ), NewNormalDist )
2107-
21082121 def test_pdf (self ):
21092122 NormalDist = statistics .NormalDist
21102123 X = NormalDist (100 , 15 )
@@ -2151,8 +2164,8 @@ def test_cdf(self):
21512164 self .assertEqual (set (map (type , cdfs )), {float })
21522165 # Verify montonic
21532166 self .assertEqual (cdfs , sorted (cdfs ))
2154- # Verify center
2155- self .assertAlmostEqual (X .cdf (100 ), 0.50 )
2167+ # Verify center (should be exact)
2168+ self .assertEqual (X .cdf (100 ), 0.50 )
21562169 # Check against a table of known values
21572170 # https://en.wikipedia.org/wiki/Standard_normal_table#Cumulative
21582171 Z = NormalDist ()
@@ -2216,10 +2229,11 @@ def test_inv_cdf(self):
22162229 p = 1.0 - p
22172230 self .assertAlmostEqual (iq .cdf (iq .inv_cdf (p )), p )
22182231
2219- # Now apply cdf() first. At six sigmas, the round-trip
2220- # loses a lot of precision, so only check to 6 places.
2221- for x in range (10 , 190 ):
2222- self .assertAlmostEqual (iq .inv_cdf (iq .cdf (x )), x , places = 6 )
2232+ # Now apply cdf() first. Near the tails, the round-trip loses
2233+ # precision and is ill-conditioned (small changes in the inputs
2234+ # give large changes in the output), so only check to 5 places.
2235+ for x in range (200 ):
2236+ self .assertAlmostEqual (iq .inv_cdf (iq .cdf (x )), x , places = 5 )
22232237
22242238 # Error cases:
22252239 with self .assertRaises (statistics .StatisticsError ):
@@ -2237,6 +2251,9 @@ def test_inv_cdf(self):
22372251 iq .sigma = - 0.1 # sigma under zero
22382252 iq .inv_cdf (0.5 )
22392253
2254+ # Special values
2255+ self .assertTrue (math .isnan (Z .inv_cdf (float ('NaN' ))))
2256+
22402257 def test_overlap (self ):
22412258 NormalDist = statistics .NormalDist
22422259
@@ -2275,6 +2292,7 @@ def overlap_numeric(X, Y, *, steps=8_192, z=5):
22752292 (NormalDist (- 100 , 15 ), NormalDist (110 , 15 )),
22762293 (NormalDist (- 100 , 15 ), NormalDist (- 110 , 15 )),
22772294 # Misc cases with unequal standard deviations
2295+ (NormalDist (100 , 12 ), NormalDist (100 , 15 )),
22782296 (NormalDist (100 , 12 ), NormalDist (110 , 15 )),
22792297 (NormalDist (100 , 12 ), NormalDist (150 , 15 )),
22802298 (NormalDist (100 , 12 ), NormalDist (150 , 35 )),
@@ -2305,18 +2323,6 @@ def test_properties(self):
23052323 self .assertEqual (X .stdev , 15 )
23062324 self .assertEqual (X .variance , 225 )
23072325
2308- def test_unary_operations (self ):
2309- NormalDist = statistics .NormalDist
2310- X = NormalDist (100 , 12 )
2311- Y = + X
2312- self .assertIsNot (X , Y )
2313- self .assertEqual (X .mu , Y .mu )
2314- self .assertEqual (X .sigma , Y .sigma )
2315- Y = - X
2316- self .assertIsNot (X , Y )
2317- self .assertEqual (X .mu , - Y .mu )
2318- self .assertEqual (X .sigma , Y .sigma )
2319-
23202326 def test_same_type_addition_and_subtraction (self ):
23212327 NormalDist = statistics .NormalDist
23222328 X = NormalDist (100 , 12 )
@@ -2340,13 +2346,27 @@ def test_translation_and_scaling(self):
23402346 with self .assertRaises (TypeError ): # __rtruediv__
23412347 y / X
23422348
2349+ def test_unary_operations (self ):
2350+ NormalDist = statistics .NormalDist
2351+ X = NormalDist (100 , 12 )
2352+ Y = + X
2353+ self .assertIsNot (X , Y )
2354+ self .assertEqual (X .mu , Y .mu )
2355+ self .assertEqual (X .sigma , Y .sigma )
2356+ Y = - X
2357+ self .assertIsNot (X , Y )
2358+ self .assertEqual (X .mu , - Y .mu )
2359+ self .assertEqual (X .sigma , Y .sigma )
2360+
23432361 def test_equality (self ):
23442362 NormalDist = statistics .NormalDist
23452363 nd1 = NormalDist ()
23462364 nd2 = NormalDist (2 , 4 )
23472365 nd3 = NormalDist ()
2366+ nd4 = NormalDist (2 , 4 )
23482367 self .assertNotEqual (nd1 , nd2 )
23492368 self .assertEqual (nd1 , nd3 )
2369+ self .assertEqual (nd2 , nd4 )
23502370
23512371 # Test NotImplemented when types are different
23522372 class A :
0 commit comments