use strafe_type::{FloatConstraint, Positive64, Real64};
use crate::{
distribution::func::{ebd0, stirlerr},
func::lgamma,
traits::DPQ,
};
const M_SQRT_2PI: f64 = 2.50662827463100050241576528481104525301;
const M_2PI: f64 = 6.283185307179586476925286766559;
const x_LRG: f64 = 2.86111748575702815380240589208115399625e+307;
pub fn dpois_raw(x: f64, lambda: f64, log: bool) -> f64 {
if lambda == 0.0 {
return if x == 0.0 {
f64::d_1(log)
} else {
f64::d_0(log)
};
} if !lambda.is_finite() {
return f64::d_0(log);
}
if x < 0.0 {
return f64::d_0(log);
}
if x <= lambda * 2.2250738585072014e-308 {
return (-lambda).d_exp(log);
}
if lambda < x * 2.2250738585072014e-308 {
if !x.is_finite() {
return f64::d_0(log);
}
return (-lambda + x * lambda.ln() - lgamma(x + 1.0).unwrap()).d_exp(log);
}
let mut yh = 0.0;
let mut yl = 0.0;
ebd0(x, lambda, &mut yh, &mut yl);
yl += stirlerr(x);
let Lrg_x = x >= x_LRG; let r = if Lrg_x {
M_SQRT_2PI * x.sqrt() } else {
M_2PI * x
};
if log {
-yl - yh - (if Lrg_x { r.ln() } else { 0.5 * r.ln() })
} else {
(-yl).exp() * (-yh).exp() / (if Lrg_x { r } else { r.sqrt() })
}
}
pub fn dpois<R: Into<Real64>, P: Into<Positive64>>(x: R, lambda: P, log: bool) -> Real64 {
let mut x = x.into().unwrap();
let lambda = lambda.into().unwrap();
if x.is_non_integer() {
warn!("non-integer x = {}", x);
return f64::d_0(log).into();
}
if x < 0.0 || !x.is_finite() {
return f64::d_0(log).into();
}
x = x.round();
dpois_raw(x, lambda, log).into()
}