See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions; 4 5 use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; 6 use PhpOffice\PhpSpreadsheet\Calculation\Exception; 7 use PhpOffice\PhpSpreadsheet\Calculation\Functions; 8 use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 9 use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Combinations; 10 11 class Binomial 12 { 13 use ArrayEnabled; 14 15 /** 16 * BINOMDIST. 17 * 18 * Returns the individual term binomial distribution probability. Use BINOMDIST in problems with 19 * a fixed number of tests or trials, when the outcomes of any trial are only success or failure, 20 * when trials are independent, and when the probability of success is constant throughout the 21 * experiment. For example, BINOMDIST can calculate the probability that two of the next three 22 * babies born are male. 23 * 24 * @param mixed $value Integer number of successes in trials 25 * Or can be an array of values 26 * @param mixed $trials Integer umber of trials 27 * Or can be an array of values 28 * @param mixed $probability Probability of success on each trial as a float 29 * Or can be an array of values 30 * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) 31 * Or can be an array of values 32 * 33 * @return array|float|string 34 * If an array of numbers is passed as an argument, then the returned result will also be an array 35 * with the same dimensions 36 */ 37 public static function distribution($value, $trials, $probability, $cumulative) 38 { 39 if (is_array($value) || is_array($trials) || is_array($probability) || is_array($cumulative)) { 40 return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $trials, $probability, $cumulative); 41 } 42 43 try { 44 $value = DistributionValidations::validateInt($value); 45 $trials = DistributionValidations::validateInt($trials); 46 $probability = DistributionValidations::validateProbability($probability); 47 $cumulative = DistributionValidations::validateBool($cumulative); 48 } catch (Exception $e) { 49 return $e->getMessage(); 50 } 51 52 if (($value < 0) || ($value > $trials)) { 53 return ExcelError::NAN(); 54 } 55 56 if ($cumulative) { 57 return self::calculateCumulativeBinomial($value, $trials, $probability); 58 } 59 /** @var float */ 60 $comb = Combinations::withoutRepetition($trials, $value); 61 62 return $comb * $probability ** $value 63 * (1 - $probability) ** ($trials - $value); 64 } 65 66 /** 67 * BINOM.DIST.RANGE. 68 * 69 * Returns returns the Binomial Distribution probability for the number of successes from a specified number 70 * of trials falling into a specified range. 71 * 72 * @param mixed $trials Integer number of trials 73 * Or can be an array of values 74 * @param mixed $probability Probability of success on each trial as a float 75 * Or can be an array of values 76 * @param mixed $successes The integer number of successes in trials 77 * Or can be an array of values 78 * @param mixed $limit Upper limit for successes in trials as null, or an integer 79 * If null, then this will indicate the same as the number of Successes 80 * Or can be an array of values 81 * 82 * @return array|float|string 83 * If an array of numbers is passed as an argument, then the returned result will also be an array 84 * with the same dimensions 85 */ 86 public static function range($trials, $probability, $successes, $limit = null) 87 { 88 if (is_array($trials) || is_array($probability) || is_array($successes) || is_array($limit)) { 89 return self::evaluateArrayArguments([self::class, __FUNCTION__], $trials, $probability, $successes, $limit); 90 } 91 92 $limit = $limit ?? $successes; 93 94 try { 95 $trials = DistributionValidations::validateInt($trials); 96 $probability = DistributionValidations::validateProbability($probability); 97 $successes = DistributionValidations::validateInt($successes); 98 $limit = DistributionValidations::validateInt($limit); 99 } catch (Exception $e) { 100 return $e->getMessage(); 101 } 102 103 if (($successes < 0) || ($successes > $trials)) { 104 return ExcelError::NAN(); 105 } 106 if (($limit < 0) || ($limit > $trials) || $limit < $successes) { 107 return ExcelError::NAN(); 108 } 109 110 $summer = 0; 111 for ($i = $successes; $i <= $limit; ++$i) { 112 /** @var float */ 113 $comb = Combinations::withoutRepetition($trials, $i); 114 $summer += $comb * $probability ** $i 115 * (1 - $probability) ** ($trials - $i); 116 } 117 118 return $summer; 119 } 120 121 /** 122 * NEGBINOMDIST. 123 * 124 * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that 125 * there will be number_f failures before the number_s-th success, when the constant 126 * probability of a success is probability_s. This function is similar to the binomial 127 * distribution, except that the number of successes is fixed, and the number of trials is 128 * variable. Like the binomial, trials are assumed to be independent. 129 * 130 * @param mixed $failures Number of Failures as an integer 131 * Or can be an array of values 132 * @param mixed $successes Threshold number of Successes as an integer 133 * Or can be an array of values 134 * @param mixed $probability Probability of success on each trial as a float 135 * Or can be an array of values 136 * 137 * @return array|float|string The result, or a string containing an error 138 * If an array of numbers is passed as an argument, then the returned result will also be an array 139 * with the same dimensions 140 * 141 * TODO Add support for the cumulative flag not present for NEGBINOMDIST, but introduced for NEGBINOM.DIST 142 * The cumulative default should be false to reflect the behaviour of NEGBINOMDIST 143 */ 144 public static function negative($failures, $successes, $probability) 145 { 146 if (is_array($failures) || is_array($successes) || is_array($probability)) { 147 return self::evaluateArrayArguments([self::class, __FUNCTION__], $failures, $successes, $probability); 148 } 149 150 try { 151 $failures = DistributionValidations::validateInt($failures); 152 $successes = DistributionValidations::validateInt($successes); 153 $probability = DistributionValidations::validateProbability($probability); 154 } catch (Exception $e) { 155 return $e->getMessage(); 156 } 157 158 if (($failures < 0) || ($successes < 1)) { 159 return ExcelError::NAN(); 160 } 161 if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { 162 if (($failures + $successes - 1) <= 0) { 163 return ExcelError::NAN(); 164 } 165 } 166 /** @var float */ 167 $comb = Combinations::withoutRepetition($failures + $successes - 1, $successes - 1); 168 169 return $comb 170 * ($probability ** $successes) * ((1 - $probability) ** $failures); 171 } 172 173 /** 174 * BINOM.INV. 175 * 176 * Returns the smallest value for which the cumulative binomial distribution is greater 177 * than or equal to a criterion value 178 * 179 * @param mixed $trials number of Bernoulli trials as an integer 180 * Or can be an array of values 181 * @param mixed $probability probability of a success on each trial as a float 182 * Or can be an array of values 183 * @param mixed $alpha criterion value as a float 184 * Or can be an array of values 185 * 186 * @return array|int|string 187 * If an array of numbers is passed as an argument, then the returned result will also be an array 188 * with the same dimensions 189 */ 190 public static function inverse($trials, $probability, $alpha) 191 { 192 if (is_array($trials) || is_array($probability) || is_array($alpha)) { 193 return self::evaluateArrayArguments([self::class, __FUNCTION__], $trials, $probability, $alpha); 194 } 195 196 try { 197 $trials = DistributionValidations::validateInt($trials); 198 $probability = DistributionValidations::validateProbability($probability); 199 $alpha = DistributionValidations::validateFloat($alpha); 200 } catch (Exception $e) { 201 return $e->getMessage(); 202 } 203 204 if ($trials < 0) { 205 return ExcelError::NAN(); 206 } elseif (($alpha < 0.0) || ($alpha > 1.0)) { 207 return ExcelError::NAN(); 208 } 209 210 $successes = 0; 211 while ($successes <= $trials) { 212 $result = self::calculateCumulativeBinomial($successes, $trials, $probability); 213 if ($result >= $alpha) { 214 break; 215 } 216 ++$successes; 217 } 218 219 return $successes; 220 } 221 222 /** 223 * @return float|int 224 */ 225 private static function calculateCumulativeBinomial(int $value, int $trials, float $probability) 226 { 227 $summer = 0; 228 for ($i = 0; $i <= $value; ++$i) { 229 /** @var float */ 230 $comb = Combinations::withoutRepetition($trials, $i); 231 $summer += $comb * $probability ** $i 232 * (1 - $probability) ** ($trials - $i); 233 } 234 235 return $summer; 236 } 237 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body