1+ <?php
2+
3+ declare (strict_types=1 );
4+
5+ namespace ZxcvbnPhp \Math ;
6+
7+ use ZxcvbnPhp \Math \Impl \BinomialProviderPhp73Gmp ;
8+ use ZxcvbnPhp \Math \Impl \BinomialProviderFloat64 ;
9+ use ZxcvbnPhp \Math \Impl \BinomialProviderInt64 ;
10+
11+ class Binomial
12+ {
13+ private static $ provider = null ;
14+
15+ private function __construct ()
16+ {
17+ throw new \LogicException (__CLASS__ . " is static " );
18+ }
19+
20+ /**
21+ * Calculate binomial coefficient (n choose k).
22+ *
23+ * @param int $n
24+ * @param int $k
25+ * @return float
26+ */
27+ public static function binom (int $ n , int $ k ): float
28+ {
29+ return self ::getProvider ()->binom ($ n , $ k );
30+ }
31+
32+ public static function getProvider (): BinomialProvider
33+ {
34+ if (self ::$ provider === null ) {
35+ self ::$ provider = self ::initProvider ();
36+ }
37+
38+ return self ::$ provider ;
39+ }
40+
41+ /**
42+ * @return string[]
43+ */
44+ public static function getUsableProviderClasses (): array
45+ {
46+ // In order of priority. The first provider with a value of true will be used.
47+ $ possibleProviderClasses = [
48+ BinomialProviderPhp73Gmp::class => function_exists ('gmp_binomial ' ),
49+ BinomialProviderInt64::class => PHP_INT_SIZE >= 8 ,
50+ BinomialProviderFloat64::class => PHP_FLOAT_DIG >= 15 ,
51+ ];
52+
53+ $ possibleProviderClasses = array_filter ($ possibleProviderClasses );
54+
55+ return array_keys ($ possibleProviderClasses );
56+ }
57+
58+ private static function initProvider (): BinomialProvider
59+ {
60+ $ providerClasses = self ::getUsableProviderClasses ();
61+
62+ if (!$ providerClasses ) {
63+ throw new \LogicException ("No valid providers " );
64+ }
65+
66+ $ bestProviderClass = reset ($ providerClasses );
67+
68+ return new $ bestProviderClass ();
69+ }
70+ }
0 commit comments