pub fn expinv(p: f64, mu: f64) -> f64 {
if mu.is_nan() || mu <= 0.0 {
return f64::NAN;
}
let q: f64 = if 0.0 < p && p < 1.0 {
if p < 0.125 { -f64::ln_1p(-p) } else { -f64::ln(1.0 - p) }
} else if p == 1.0 {
f64::INFINITY
} else if p < 0.0 || 1.0 < p || p.is_nan() {
f64::NAN
} else {
0.0
};
return mu * q;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::expcdf;
#[test]
fn test_expinv_standard() {
let mu = 2.0;
let p = 0.5;
let expected = mu * 2.0f64.ln();
assert!((expinv(p, mu) - expected).abs() < 1e-15);
}
#[test]
fn test_expinv_roundtrip() {
let mu = 1.5;
let values = [0.1, 0.5, 0.9, 0.99];
for &p in &values {
let x = expinv(p, mu);
let p_back = expcdf(x, mu, false);
assert!((p - p_back).abs() < 1e-15);
}
}
#[test]
fn test_expinv_boundaries() {
let mu = 2.5;
assert_eq!(expinv(0.0, mu), 0.0);
assert_eq!(expinv(1.0, mu), f64::INFINITY);
assert!(expinv(-0.1, mu).is_nan());
assert!(expinv(1.1, mu).is_nan());
assert!(expinv(0.5, 0.0).is_nan());
assert!(expinv(0.5, -1.0).is_nan());
assert!(expinv(0.5, f64::NAN).is_nan());
}
}