use crate::error::{StatsError, StatsResult};
use crate::prob::erf;
use num_traits::ToPrimitive;
#[inline]
pub fn erfc<T>(x: T) -> StatsResult<f64>
where
T: ToPrimitive,
{
let x_64 = x.to_f64().ok_or_else(|| StatsError::ConversionError {
message: "prob::erfc: Failed to convert x to f64".to_string(),
})?;
Ok(1.0 - erf(x_64)?)
}
#[cfg(test)]
mod tests {
use super::*;
const EPSILON: f64 = 1e-5;
#[test]
fn test_erfc_zero() {
let result = erfc(0.0).unwrap();
let expected = 1.0;
assert!((result - expected).abs() < EPSILON, "erfc(0) should be 1.0");
}
#[test]
fn test_erfc_positive_value() {
let result = erfc(1.0).unwrap();
let expected = 0.157299207;
assert!(
(result - expected).abs() < EPSILON,
"erfc(1.0) should be approximately 0.157299207"
);
}
#[test]
fn test_erfc_negative_value() {
let result = erfc(-1.0).unwrap();
let expected = 1.842700792;
assert!(
(result - expected).abs() < EPSILON,
"erfc(-1.0) should be approximately 1.842700792"
);
}
#[test]
fn test_erfc_large_positive_value() {
let result = erfc(3.0).unwrap();
let expected = 0.0000220905;
assert!(
(result - expected).abs() < EPSILON,
"erfc(3.0) should be approximately 0.0000220905 got {:?}",
result
);
}
#[test]
fn test_erfc_large_negative_value() {
let result = erfc(-3.0).unwrap();
let expected = 1.99997791;
assert!(
(result - expected).abs() < EPSILON,
"erfc(-3.0) should be approximately 1.99997791"
);
}
}