use crate::FloatScalar;
const DIGAMMA_ASYMP: [f64; 7] = [
1.0 / 12.0, -1.0 / 120.0, 1.0 / 252.0, -1.0 / 240.0, 1.0 / 132.0, -691.0 / 32760.0, 1.0 / 12.0, ];
pub fn digamma<T: FloatScalar>(x: T) -> T {
let zero = T::zero();
let one = T::one();
if x.is_nan() {
return x;
}
if x <= zero && x == x.floor() {
return T::nan();
}
if x < zero {
let pi = T::from(core::f64::consts::PI).unwrap();
let tan_pi_x = (pi * x).tan();
return digamma(one - x) - pi / tan_pi_x;
}
let mut result = zero;
let mut xx = x;
let threshold = T::from(6.0).unwrap();
while xx < threshold {
result = result - one / xx;
xx = xx + one;
}
let half = T::from(0.5).unwrap();
result = result + xx.ln() - half / xx;
let inv_x2 = one / (xx * xx);
let mut term = inv_x2;
for &c in &DIGAMMA_ASYMP {
let ci = T::from(c).unwrap();
result = result - ci * term;
term = term * inv_x2;
}
result
}