use crate::special::betai;
pub fn erfc_inv(p: f64) -> f64 {
-norm_ppf(0.5 * p) / core::f64::consts::SQRT_2
}
pub fn erf_inv(x: f64) -> f64 { erfc_inv(1.0 - x) }
fn norm_ppf(p: f64) -> f64 {
const A: [f64; 6] = [
-3.969683028665376e+01,
2.209460984245205e+02,
-2.759285104469687e+02,
1.383_577_518_672_69e2,
-3.066479806614716e+01,
2.506628277459239e+00,
];
const B: [f64; 5] = [
-5.447609879822406e+01,
1.615858368580409e+02,
-1.556989798598866e+02,
6.680131188771972e+01,
-1.328068155288572e+01,
];
const C: [f64; 6] = [
-7.784894002430293e-03,
-3.223964580411365e-01,
-2.400758277161838e+00,
-2.549732539343734e+00,
4.374664141464968e+00,
2.938163982698783e+00,
];
const D: [f64; 4] = [
7.784695709041462e-03,
3.224671290700398e-01,
2.445134137142996e+00,
3.754408661907416e+00,
];
const P_LOW: f64 = 0.02425;
const P_HIGH: f64 = 1.0 - P_LOW;
if p <= 0.0 {
return f64::NEG_INFINITY;
}
if p >= 1.0 {
return f64::INFINITY;
}
let mut x = if p < P_LOW {
let q = (-2.0 * p.ln()).sqrt();
(((((C[0] * q + C[1]) * q + C[2]) * q + C[3]) * q + C[4]) * q + C[5])
/ ((((D[0] * q + D[1]) * q + D[2]) * q + D[3]) * q + 1.0)
} else if p <= P_HIGH {
let q = p - 0.5;
let r = q * q;
(((((A[0] * r + A[1]) * r + A[2]) * r + A[3]) * r + A[4]) * r + A[5]) * q
/ (((((B[0] * r + B[1]) * r + B[2]) * r + B[3]) * r + B[4]) * r + 1.0)
} else {
let q = (-2.0 * (1.0 - p).ln()).sqrt();
-(((((C[0] * q + C[1]) * q + C[2]) * q + C[3]) * q + C[4]) * q + C[5])
/ ((((D[0] * q + D[1]) * q + D[2]) * q + D[3]) * q + 1.0)
};
if x.is_finite() {
let e = 0.5 * libm::erfc(-x / core::f64::consts::SQRT_2) - p; let u = e * (2.0 * core::f64::consts::PI).sqrt() * (x * x / 2.0).exp();
x -= u / (1.0 + x * u / 2.0);
}
x
}
pub fn inv_beta_reg(a: f64, b: f64, p: f64) -> f64 {
if p <= 0.0 { return 0.0; }
if p >= 1.0 { return 1.0; }
if p > 0.5 {
return 1.0 - inv_beta_reg_lower(b, a, 1.0 - p);
}
inv_beta_reg_lower(a, b, p)
}
fn inv_beta_reg_lower(a: f64, b: f64, p: f64) -> f64 {
let mut lo = 0.0_f64;
let mut hi = 1.0_f64;
for _ in 0..80 {
let mid = 0.5 * (lo + hi);
if mid <= lo || mid >= hi { break; } if betai(a, b, mid) < p { lo = mid; } else { hi = mid; }
}
0.5 * (lo + hi)
}