pub fn erf(x: f64) -> f64 { libm::erf(x) }
pub fn erfc(x: f64) -> f64 { libm::erfc(x) }
pub fn gamma(x: f64) -> f64 { libm::tgamma(x) }
pub fn lgamma(mut x: f64) -> f64 {
const G: f64 = 7.0;
const P: [f64; 9] = [
0.999_999_999_999_809_9,
676.520_368_121_885_1,
-1_259.139_216_722_402_8,
771.323_428_777_653_1,
-176.615_029_162_140_6,
12.507_343_278_686_905,
-0.138_571_095_265_720_12,
9.984_369_578_019_572e-6,
1.505_632_735_149_311_6e-7,
];
if x < 0.5 {
return (std::f64::consts::PI / (std::f64::consts::PI * x).sin()).ln() - lgamma(1.0 - x);
}
x -= 1.0;
let mut a = P[0];
let t = x + G + 0.5;
for (i, &pi) in P.iter().enumerate().skip(1) {
a += pi / (x + i as f64);
}
0.5 * (2.0 * std::f64::consts::PI).ln() + (x + 0.5) * t.ln() - t + a.ln()
}
pub fn beta(a: f64, b: f64) -> f64 { lbeta(a, b).exp() }
pub fn lbeta(a: f64, b: f64) -> f64 { lgamma(a) + lgamma(b) - lgamma(a + b) }