double gammaincinv(double a, double y) { double lo = 0.0, hi; double flo = -y, fhi = 0.25 - y; double params[2]; double best_x, best_f, errest; fsolve_result_t r; if (a <= 0.0 || y <= 0.0 || y >= 0.25) { return cephes_igami(a, 1-y); } /* Note: flo and fhi must have different signs (and be != 0), * otherwise fsolve terminates with an error. */ params[0] = a; params[1] = y; hi = cephes_igami(a, 0.75); /* I found Newton to be unreliable. Also, after we generate a small interval by bisection above, false position will do a large step from an interval of width ~1e-4 to ~1e-14 in one step (a=10, x=0.05, but similiar for other values). */ r = false_position(&lo, &flo, &hi, &fhi, (objective_function)gammainc, params, 2*MACHEP, 2*MACHEP, 1e-2*a, &best_x, &best_f, &errest); if (!(r == FSOLVE_CONVERGED || r == FSOLVE_EXACT) && errest > ALLOWED_ATOL + ALLOWED_RTOL*fabs(best_x)) { sf_error("gammaincinv", SF_ERROR_NO_RESULT, "failed to converge at (a, y) = (%.20g, %.20g): got %g +- %g, code %d\n", a, y, best_x, errest, r); best_x = NPY_NAN; } return best_x; }
double gammaincinv(double a, double y) { double lo = 0.0, hi; double flo = -y, fhi = 0.25 - y; double params[2]; double best_x, best_f, errest; fsolve_result_t r; if (a <= 0.0 || y <= 0.0 || y >= 0.25) { return igami(a, 1-y); } /* Note: flo and fhi must have different signs (and be != 0), * otherwise fsolve terminates with an error. */ params[0] = a; params[1] = y; hi = igami(a, 0.75); /* I found Newton to be unreliable. Also, after we generate a small interval by bisection above, false position will do a large step from an interval of width ~1e-4 to ~1e-14 in one step (a=10, x=0.05, but similiar for other values). */ r = false_position(&lo, &flo, &hi, &fhi, (objective_function)gammainc, params, 2*MACHEP, 2*MACHEP, 1e-2*a, &best_x, &best_f, &errest); if (!(r == FSOLVE_CONVERGED || r == FSOLVE_EXACT) && errest > ALLOWED_ATOL + ALLOWED_RTOL*fabs(best_x)) { best_x = GAMMAINCINV_NaN; } return best_x; }