@@ 1062-1106 (lines=45) @@ | ||
1059 | * @param float $degrees degrees of freedom |
|
1060 | * @return float |
|
1061 | */ |
|
1062 | public static function CHIINV($probability, $degrees) |
|
1063 | { |
|
1064 | $probability = Functions::flattenSingleValue($probability); |
|
1065 | $degrees = floor(Functions::flattenSingleValue($degrees)); |
|
1066 | ||
1067 | if ((is_numeric($probability)) && (is_numeric($degrees))) { |
|
1068 | $xLo = 100; |
|
1069 | $xHi = 0; |
|
1070 | ||
1071 | $x = $xNew = 1; |
|
1072 | $dx = 1; |
|
1073 | $i = 0; |
|
1074 | ||
1075 | while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { |
|
1076 | // Apply Newton-Raphson step |
|
1077 | $result = self::CHIDIST($x, $degrees); |
|
1078 | $error = $result - $probability; |
|
1079 | if ($error == 0.0) { |
|
1080 | $dx = 0; |
|
1081 | } elseif ($error < 0.0) { |
|
1082 | $xLo = $x; |
|
1083 | } else { |
|
1084 | $xHi = $x; |
|
1085 | } |
|
1086 | // Avoid division by zero |
|
1087 | if ($result != 0.0) { |
|
1088 | $dx = $error / $result; |
|
1089 | $xNew = $x - $dx; |
|
1090 | } |
|
1091 | // If the NR fails to converge (which for example may be the |
|
1092 | // case if the initial guess is too rough) we apply a bisection |
|
1093 | // step to determine a more narrow interval around the root. |
|
1094 | if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { |
|
1095 | $xNew = ($xLo + $xHi) / 2; |
|
1096 | $dx = $xNew - $x; |
|
1097 | } |
|
1098 | $x = $xNew; |
|
1099 | } |
|
1100 | if ($i == MAX_ITERATIONS) { |
|
1101 | return Functions::NA(); |
|
1102 | } |
|
1103 | return round($x, 12); |
|
1104 | } |
|
1105 | return Functions::VALUE(); |
|
1106 | } |
|
1107 | ||
1108 | ||
1109 | /** |
|
@@ 3354-3398 (lines=45) @@ | ||
3351 | * @param float $degrees degrees of freedom |
|
3352 | * @return float |
|
3353 | */ |
|
3354 | public static function TINV($probability, $degrees) |
|
3355 | { |
|
3356 | $probability = Functions::flattenSingleValue($probability); |
|
3357 | $degrees = floor(Functions::flattenSingleValue($degrees)); |
|
3358 | ||
3359 | if ((is_numeric($probability)) && (is_numeric($degrees))) { |
|
3360 | $xLo = 100; |
|
3361 | $xHi = 0; |
|
3362 | ||
3363 | $x = $xNew = 1; |
|
3364 | $dx = 1; |
|
3365 | $i = 0; |
|
3366 | ||
3367 | while ((abs($dx) > PRECISION) && ($i++ < MAX_ITERATIONS)) { |
|
3368 | // Apply Newton-Raphson step |
|
3369 | $result = self::TDIST($x, $degrees, 2); |
|
3370 | $error = $result - $probability; |
|
3371 | if ($error == 0.0) { |
|
3372 | $dx = 0; |
|
3373 | } elseif ($error < 0.0) { |
|
3374 | $xLo = $x; |
|
3375 | } else { |
|
3376 | $xHi = $x; |
|
3377 | } |
|
3378 | // Avoid division by zero |
|
3379 | if ($result != 0.0) { |
|
3380 | $dx = $error / $result; |
|
3381 | $xNew = $x - $dx; |
|
3382 | } |
|
3383 | // If the NR fails to converge (which for example may be the |
|
3384 | // case if the initial guess is too rough) we apply a bisection |
|
3385 | // step to determine a more narrow interval around the root. |
|
3386 | if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { |
|
3387 | $xNew = ($xLo + $xHi) / 2; |
|
3388 | $dx = $xNew - $x; |
|
3389 | } |
|
3390 | $x = $xNew; |
|
3391 | } |
|
3392 | if ($i == MAX_ITERATIONS) { |
|
3393 | return Functions::NA(); |
|
3394 | } |
|
3395 | return round($x, 12); |
|
3396 | } |
|
3397 | return Functions::VALUE(); |
|
3398 | } |
|
3399 | ||
3400 | ||
3401 | /** |