| @@ 1043-1087 (lines=45) @@ | ||
| 1040 | * @param float $degrees degrees of freedom |
|
| 1041 | * @return float |
|
| 1042 | */ |
|
| 1043 | public static function CHIINV($probability, $degrees) { |
|
| 1044 | $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); |
|
| 1045 | $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees)); |
|
| 1046 | ||
| 1047 | if ((is_numeric($probability)) && (is_numeric($degrees))) { |
|
| 1048 | ||
| 1049 | $xLo = 100; |
|
| 1050 | $xHi = 0; |
|
| 1051 | ||
| 1052 | $x = $xNew = 1; |
|
| 1053 | $dx = 1; |
|
| 1054 | $i = 0; |
|
| 1055 | ||
| 1056 | while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { |
|
| 1057 | // Apply Newton-Raphson step |
|
| 1058 | $result = self::CHIDIST($x, $degrees); |
|
| 1059 | $error = $result - $probability; |
|
| 1060 | if ($error == 0.0) { |
|
| 1061 | $dx = 0; |
|
| 1062 | } elseif ($error < 0.0) { |
|
| 1063 | $xLo = $x; |
|
| 1064 | } else { |
|
| 1065 | $xHi = $x; |
|
| 1066 | } |
|
| 1067 | // Avoid division by zero |
|
| 1068 | if ($result != 0.0) { |
|
| 1069 | $dx = $error / $result; |
|
| 1070 | $xNew = $x - $dx; |
|
| 1071 | } |
|
| 1072 | // If the NR fails to converge (which for example may be the |
|
| 1073 | // case if the initial guess is too rough) we apply a bisection |
|
| 1074 | // step to determine a more narrow interval around the root. |
|
| 1075 | if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { |
|
| 1076 | $xNew = ($xLo + $xHi) / 2; |
|
| 1077 | $dx = $xNew - $x; |
|
| 1078 | } |
|
| 1079 | $x = $xNew; |
|
| 1080 | } |
|
| 1081 | if ($i == MAX_ITERATIONS) { |
|
| 1082 | return PHPExcel_Calculation_Functions::NA(); |
|
| 1083 | } |
|
| 1084 | return round($x,12); |
|
| 1085 | } |
|
| 1086 | return PHPExcel_Calculation_Functions::VALUE(); |
|
| 1087 | } // function CHIINV() |
|
| 1088 | ||
| 1089 | ||
| 1090 | /** |
|
| @@ 3272-3315 (lines=44) @@ | ||
| 3269 | * @param float $degrees degrees of freedom |
|
| 3270 | * @return float |
|
| 3271 | */ |
|
| 3272 | public static function TINV($probability, $degrees) { |
|
| 3273 | $probability = PHPExcel_Calculation_Functions::flattenSingleValue($probability); |
|
| 3274 | $degrees = floor(PHPExcel_Calculation_Functions::flattenSingleValue($degrees)); |
|
| 3275 | ||
| 3276 | if ((is_numeric($probability)) && (is_numeric($degrees))) { |
|
| 3277 | $xLo = 100; |
|
| 3278 | $xHi = 0; |
|
| 3279 | ||
| 3280 | $x = $xNew = 1; |
|
| 3281 | $dx = 1; |
|
| 3282 | $i = 0; |
|
| 3283 | ||
| 3284 | while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { |
|
| 3285 | // Apply Newton-Raphson step |
|
| 3286 | $result = self::TDIST($x, $degrees, 2); |
|
| 3287 | $error = $result - $probability; |
|
| 3288 | if ($error == 0.0) { |
|
| 3289 | $dx = 0; |
|
| 3290 | } elseif ($error < 0.0) { |
|
| 3291 | $xLo = $x; |
|
| 3292 | } else { |
|
| 3293 | $xHi = $x; |
|
| 3294 | } |
|
| 3295 | // Avoid division by zero |
|
| 3296 | if ($result != 0.0) { |
|
| 3297 | $dx = $error / $result; |
|
| 3298 | $xNew = $x - $dx; |
|
| 3299 | } |
|
| 3300 | // If the NR fails to converge (which for example may be the |
|
| 3301 | // case if the initial guess is too rough) we apply a bisection |
|
| 3302 | // step to determine a more narrow interval around the root. |
|
| 3303 | if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { |
|
| 3304 | $xNew = ($xLo + $xHi) / 2; |
|
| 3305 | $dx = $xNew - $x; |
|
| 3306 | } |
|
| 3307 | $x = $xNew; |
|
| 3308 | } |
|
| 3309 | if ($i == MAX_ITERATIONS) { |
|
| 3310 | return PHPExcel_Calculation_Functions::NA(); |
|
| 3311 | } |
|
| 3312 | return round($x,12); |
|
| 3313 | } |
|
| 3314 | return PHPExcel_Calculation_Functions::VALUE(); |
|
| 3315 | } // function TINV() |
|
| 3316 | ||
| 3317 | ||
| 3318 | /** |
|