use num_traits::ToPrimitive;
use std::f64::consts;
#[doc(hidden)]
pub fn gamma(mut x: f64) -> f64 {
const G: f64 = 4.742_187_5;
const P: [f64; 15] = [
0.999_999_999_999_997_1,
57.156_235_665_862_92,
-59.597_960_355_475_49,
14.136_097_974_741_746,
-0.491_913_816_097_620_2,
0.000_033_994_649_984_811_89,
0.000_046_523_628_927_048_58,
-0.000_098_374_475_304_879_56,
0.000_158_088_703_224_912_5,
-0.000_210_264_441_724_104_88,
0.000_217_439_618_115_212_65,
-0.000_164_318_106_536_763_9,
0.000_084_418_223_983_852_75,
-0.000_026_190_838_401_581_408,
0.000_003_689_918_265_953_162_5,
];
if x < 0.5 {
consts::PI / (f64::sin(consts::PI * x) * gamma(1.0 - x))
} else {
x -= 1.0;
let mut factor: f64 = P[0];
for (n, coefficient) in P.iter().enumerate().skip(1) {
factor += coefficient / (x + n.to_f64().unwrap());
}
let t: f64 = x + G + 0.5;
f64::sqrt(2.0 * consts::PI) * f64::powf(t, x + 0.5) * f64::exp(-t) * factor
}
}
#[cfg(test)]
mod tests {
use super::*;
fn gamma_fact(n: f64) -> f64 {
gamma(n + 1.0)
}
fn f64_eq(a: f64, b: f64, delta: f64) -> bool {
a.abs() - b.abs() < delta
}
#[test]
fn gamma_test() {
const ERROR: f64 = 0.00000000001;
assert!(f64_eq(
gamma_fact(0.9),
0.96176583190738741940757480212503,
ERROR
));
assert!(f64_eq(
gamma_fact(0.5),
0.88622692545275801364908374167057,
ERROR
));
assert!(f64_eq(
gamma_fact(0.1),
0.95135076986687318362924871772654,
ERROR
));
}
}