11"""For more information about the Binomial Distribution -
22https://en.wikipedia.org/wiki/Binomial_distribution"""
33
4- from math import factorial
4+ from math import comb , exp , lgamma , log , log1p
5+ from sys import float_info
56
67
78def binomial_distribution (successes : int , trials : int , prob : float ) -> float :
89 """
910 Return probability of k successes out of n tries, with p probability for one
1011 success
1112
12- The function uses the factorial function in order to calculate the binomial
13- coefficient
13+ The function uses math.comb for direct calculation and switches to
14+ a logarithmic approach for numerically challenging inputs.
1415
1516 >>> binomial_distribution(3, 5, 0.7)
1617 0.30870000000000003
1718 >>> binomial_distribution (2, 4, 0.5)
1819 0.375
20+ >>> round(binomial_distribution(85, 171, 0.5), 12)
21+ 0.060749764626
22+ >>> round(binomial_distribution(5000, 10000, 0.5), 10)
23+ 0.0079786461
1924 """
2025 if successes > trials :
2126 raise ValueError ("""successes must be lower or equal to trials""" )
@@ -25,11 +30,31 @@ def binomial_distribution(successes: int, trials: int, prob: float) -> float:
2530 raise ValueError ("the function is defined for non-negative integers" )
2631 if not 0 < prob < 1 :
2732 raise ValueError ("prob has to be in range of 1 - 0" )
28- probability = (prob ** successes ) * ((1 - prob ) ** (trials - successes ))
29- # Calculate the binomial coefficient: n! / k!(n-k)!
30- coefficient = float (factorial (trials ))
31- coefficient /= factorial (successes ) * factorial (trials - successes )
32- return probability * coefficient
33+ success_term = prob ** successes
34+ failure_term = (1 - prob ) ** (trials - successes )
35+ probability_terms = success_term * failure_term
36+ log_coefficient = (
37+ lgamma (trials + 1 ) - lgamma (successes + 1 ) - lgamma (trials - successes + 1 )
38+ )
39+
40+ if (
41+ success_term > 0
42+ and failure_term > 0
43+ and probability_terms > 0
44+ and log_coefficient < log (float_info .max ) - 1
45+ ):
46+ coefficient = comb (trials , successes )
47+
48+ try :
49+ return probability_terms * coefficient
50+ except OverflowError :
51+ pass
52+
53+ log_probability = (
54+ log_coefficient + successes * log (prob ) + (trials - successes ) * log1p (- prob )
55+ )
56+
57+ return exp (log_probability )
3358
3459
3560if __name__ == "__main__" :
0 commit comments