Differences Between: [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions; 4 5 use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; 6 use PhpOffice\PhpSpreadsheet\Calculation\Engineering; 7 use PhpOffice\PhpSpreadsheet\Calculation\Exception; 8 use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; 9 10 class Normal 11 { 12 use ArrayEnabled; 13 14 public const SQRT2PI = 2.5066282746310005024157652848110452530069867406099; 15 16 /** 17 * NORMDIST. 18 * 19 * Returns the normal distribution for the specified mean and standard deviation. This 20 * function has a very wide range of applications in statistics, including hypothesis 21 * testing. 22 * 23 * @param mixed $value Float value for which we want the probability 24 * Or can be an array of values 25 * @param mixed $mean Mean value as a float 26 * Or can be an array of values 27 * @param mixed $stdDev Standard Deviation as a float 28 * Or can be an array of values 29 * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) 30 * Or can be an array of values 31 * 32 * @return array|float|string The result, or a string containing an error 33 * If an array of numbers is passed as an argument, then the returned result will also be an array 34 * with the same dimensions 35 */ 36 public static function distribution($value, $mean, $stdDev, $cumulative) 37 { 38 if (is_array($value) || is_array($mean) || is_array($stdDev) || is_array($cumulative)) { 39 return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $mean, $stdDev, $cumulative); 40 } 41 42 try { 43 $value = DistributionValidations::validateFloat($value); 44 $mean = DistributionValidations::validateFloat($mean); 45 $stdDev = DistributionValidations::validateFloat($stdDev); 46 $cumulative = DistributionValidations::validateBool($cumulative); 47 } catch (Exception $e) { 48 return $e->getMessage(); 49 } 50 51 if ($stdDev < 0) { 52 return ExcelError::NAN(); 53 } 54 55 if ($cumulative) { 56 return 0.5 * (1 + Engineering\Erf::erfValue(($value - $mean) / ($stdDev * sqrt(2)))); 57 } 58 59 return (1 / (self::SQRT2PI * $stdDev)) * exp(0 - (($value - $mean) ** 2 / (2 * ($stdDev * $stdDev)))); 60 } 61 62 /** 63 * NORMINV. 64 * 65 * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation. 66 * 67 * @param mixed $probability Float probability for which we want the value 68 * Or can be an array of values 69 * @param mixed $mean Mean Value as a float 70 * Or can be an array of values 71 * @param mixed $stdDev Standard Deviation as a float 72 * Or can be an array of values 73 * 74 * @return array|float|string The result, or a string containing an error 75 * If an array of numbers is passed as an argument, then the returned result will also be an array 76 * with the same dimensions 77 */ 78 public static function inverse($probability, $mean, $stdDev) 79 { 80 if (is_array($probability) || is_array($mean) || is_array($stdDev)) { 81 return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $mean, $stdDev); 82 } 83 84 try { 85 $probability = DistributionValidations::validateProbability($probability); 86 $mean = DistributionValidations::validateFloat($mean); 87 $stdDev = DistributionValidations::validateFloat($stdDev); 88 } catch (Exception $e) { 89 return $e->getMessage(); 90 } 91 92 if ($stdDev < 0) { 93 return ExcelError::NAN(); 94 } 95 96 return (self::inverseNcdf($probability) * $stdDev) + $mean; 97 } 98 99 /* 100 * inverse_ncdf.php 101 * ------------------- 102 * begin : Friday, January 16, 2004 103 * copyright : (C) 2004 Michael Nickerson 104 * email : nickersonm@yahoo.com 105 * 106 */ 107 private static function inverseNcdf(float $p): float 108 { 109 // Inverse ncdf approximation by Peter J. Acklam, implementation adapted to 110 // PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as 111 // a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html 112 // I have not checked the accuracy of this implementation. Be aware that PHP 113 // will truncate the coeficcients to 14 digits. 114 115 // You have permission to use and distribute this function freely for 116 // whatever purpose you want, but please show common courtesy and give credit 117 // where credit is due. 118 119 // Input paramater is $p - probability - where 0 < p < 1. 120 121 // Coefficients in rational approximations 122 static $a = [ 123 1 => -3.969683028665376e+01, 124 2 => 2.209460984245205e+02, 125 3 => -2.759285104469687e+02, 126 4 => 1.383577518672690e+02, 127 5 => -3.066479806614716e+01, 128 6 => 2.506628277459239e+00, 129 ]; 130 131 static $b = [ 132 1 => -5.447609879822406e+01, 133 2 => 1.615858368580409e+02, 134 3 => -1.556989798598866e+02, 135 4 => 6.680131188771972e+01, 136 5 => -1.328068155288572e+01, 137 ]; 138 139 static $c = [ 140 1 => -7.784894002430293e-03, 141 2 => -3.223964580411365e-01, 142 3 => -2.400758277161838e+00, 143 4 => -2.549732539343734e+00, 144 5 => 4.374664141464968e+00, 145 6 => 2.938163982698783e+00, 146 ]; 147 148 static $d = [ 149 1 => 7.784695709041462e-03, 150 2 => 3.224671290700398e-01, 151 3 => 2.445134137142996e+00, 152 4 => 3.754408661907416e+00, 153 ]; 154 155 // Define lower and upper region break-points. 156 $p_low = 0.02425; //Use lower region approx. below this 157 $p_high = 1 - $p_low; //Use upper region approx. above this 158 159 if (0 < $p && $p < $p_low) { 160 // Rational approximation for lower region. 161 $q = sqrt(-2 * log($p)); 162 163 return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / 164 (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); 165 } elseif ($p_high < $p && $p < 1) { 166 // Rational approximation for upper region. 167 $q = sqrt(-2 * log(1 - $p)); 168 169 return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / 170 (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); 171 } 172 173 // Rational approximation for central region. 174 $q = $p - 0.5; 175 $r = $q * $q; 176 177 return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q / 178 ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1); 179 } 180 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body