use crate::consts::SQRT_2PI;
pub fn lognpdf(x: f64, mu: f64, sigma: f64) -> f64 {
if x.is_nan() || mu.is_nan() || sigma.is_nan() || sigma <= 0.0 {
return f64::NAN;
}
if x <= 0.0 {
return 0.0;
}
let log_x = x.ln();
let z = (log_x - mu) / sigma;
(-0.5 * z * z).exp() / (x * sigma * SQRT_2PI)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lognpdf_standard() {
let tol = 1e-15;
assert!((lognpdf(1.0, 0.0, 1.0) - 3.9894228040143268e-1).abs() < tol);
assert!((lognpdf(2.0, 0.0, 1.0) - 1.5687401927898109e-1).abs() < tol);
assert!((lognpdf(0.5, 0.0, 1.0) - 6.2749607711592437e-1).abs() < tol);
}
#[test]
fn test_lognpdf_varied_params() {
let tol = 1e-15;
assert!((lognpdf(2.718281828459045, 1.0, 0.5) - 2.935253263474799e-01).abs() < tol); assert!((lognpdf(1.0, 1.0, 0.5) - 1.079819330263761e-01).abs() < tol); }
#[test]
fn test_lognpdf_edge_cases() {
assert!(lognpdf(f64::NAN, 0.0, 1.0).is_nan());
assert!(lognpdf(1.0, f64::NAN, 1.0).is_nan());
assert!(lognpdf(1.0, 0.0, f64::NAN).is_nan());
assert!(lognpdf(1.0, 0.0, 0.0).is_nan());
assert!(lognpdf(1.0, 0.0, -1.0).is_nan());
assert_eq!(lognpdf(0.0, 0.0, 1.0), 0.0);
assert_eq!(lognpdf(-1.0, 0.0, 1.0), 0.0);
}
}