@@ 1057-1101 (lines=45) @@ | ||
1054 | * @param float $degrees degrees of freedom |
|
1055 | * @return float |
|
1056 | */ |
|
1057 | public static function CHIINV($probability, $degrees) |
|
1058 | { |
|
1059 | $probability = Functions::flattenSingleValue($probability); |
|
1060 | $degrees = floor(Functions::flattenSingleValue($degrees)); |
|
1061 | ||
1062 | if ((is_numeric($probability)) && (is_numeric($degrees))) { |
|
1063 | $xLo = 100; |
|
1064 | $xHi = 0; |
|
1065 | ||
1066 | $x = $xNew = 1; |
|
1067 | $dx = 1; |
|
1068 | $i = 0; |
|
1069 | ||
1070 | while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { |
|
1071 | // Apply Newton-Raphson step |
|
1072 | $result = self::CHIDIST($x, $degrees); |
|
1073 | $error = $result - $probability; |
|
1074 | if ($error == 0.0) { |
|
1075 | $dx = 0; |
|
1076 | } elseif ($error < 0.0) { |
|
1077 | $xLo = $x; |
|
1078 | } else { |
|
1079 | $xHi = $x; |
|
1080 | } |
|
1081 | // Avoid division by zero |
|
1082 | if ($result != 0.0) { |
|
1083 | $dx = $error / $result; |
|
1084 | $xNew = $x - $dx; |
|
1085 | } |
|
1086 | // If the NR fails to converge (which for example may be the |
|
1087 | // case if the initial guess is too rough) we apply a bisection |
|
1088 | // step to determine a more narrow interval around the root. |
|
1089 | if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { |
|
1090 | $xNew = ($xLo + $xHi) / 2; |
|
1091 | $dx = $xNew - $x; |
|
1092 | } |
|
1093 | $x = $xNew; |
|
1094 | } |
|
1095 | if ($i == MAX_ITERATIONS) { |
|
1096 | return Functions::NA(); |
|
1097 | } |
|
1098 | ||
1099 | return round($x, 12); |
|
1100 | } |
|
1101 | ||
1102 | return Functions::VALUE(); |
|
1103 | } |
|
1104 | ||
@@ 3316-3360 (lines=45) @@ | ||
3313 | * @param float $degrees degrees of freedom |
|
3314 | * @return float |
|
3315 | */ |
|
3316 | public static function TINV($probability, $degrees) |
|
3317 | { |
|
3318 | $probability = Functions::flattenSingleValue($probability); |
|
3319 | $degrees = floor(Functions::flattenSingleValue($degrees)); |
|
3320 | ||
3321 | if ((is_numeric($probability)) && (is_numeric($degrees))) { |
|
3322 | $xLo = 100; |
|
3323 | $xHi = 0; |
|
3324 | ||
3325 | $x = $xNew = 1; |
|
3326 | $dx = 1; |
|
3327 | $i = 0; |
|
3328 | ||
3329 | while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { |
|
3330 | // Apply Newton-Raphson step |
|
3331 | $result = self::TDIST($x, $degrees, 2); |
|
3332 | $error = $result - $probability; |
|
3333 | if ($error == 0.0) { |
|
3334 | $dx = 0; |
|
3335 | } elseif ($error < 0.0) { |
|
3336 | $xLo = $x; |
|
3337 | } else { |
|
3338 | $xHi = $x; |
|
3339 | } |
|
3340 | // Avoid division by zero |
|
3341 | if ($result != 0.0) { |
|
3342 | $dx = $error / $result; |
|
3343 | $xNew = $x - $dx; |
|
3344 | } |
|
3345 | // If the NR fails to converge (which for example may be the |
|
3346 | // case if the initial guess is too rough) we apply a bisection |
|
3347 | // step to determine a more narrow interval around the root. |
|
3348 | if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { |
|
3349 | $xNew = ($xLo + $xHi) / 2; |
|
3350 | $dx = $xNew - $x; |
|
3351 | } |
|
3352 | $x = $xNew; |
|
3353 | } |
|
3354 | if ($i == MAX_ITERATIONS) { |
|
3355 | return Functions::NA(); |
|
3356 | } |
|
3357 | ||
3358 | return round($x, 12); |
|
3359 | } |
|
3360 | ||
3361 | return Functions::VALUE(); |
|
3362 | } |
|
3363 |