use crate::{SignificanceLevel, ValidationError, validate_probability};
use num_traits::{Float, FromPrimitive, ToPrimitive};
use std::fmt;
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct ConfidenceLevel<T>(T);
impl<T: ToPrimitive> fmt::Display for ConfidenceLevel<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let percent = self.0.to_f64().ok_or(fmt::Error)? * 100.0;
match f.precision() {
Some(p) => write!(f, "{percent:.p$}%"),
None => write!(f, "{percent:.1}%"),
}
}
}
macro_rules! impl_confidence_constants {
($t:ty) => {
impl ConfidenceLevel<$t> {
pub const CL90: Self = Self(0.90);
pub const CL95: Self = Self(0.95);
pub const CL975: Self = Self(0.975);
pub const CL99: Self = Self(0.99);
pub const CL999: Self = Self(0.999);
}
};
}
impl_confidence_constants!(f32);
impl_confidence_constants!(f64);
impl<T> ConfidenceLevel<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: Float> ConfidenceLevel<T> {
pub fn new(probability: T) -> Result<Self, ValidationError> {
let level = validate_probability(probability)?;
Ok(Self(level))
}
pub fn significance(self) -> SignificanceLevel<T> {
SignificanceLevel::new(T::one() - self.0).unwrap() }
}
impl<T: Float + FromPrimitive> ConfidenceLevel<T> {
pub fn from_percent(percentage: T) -> Result<Self, ValidationError> {
let level = validate_probability(percentage / T::from_f64(100.0).unwrap())?;
Ok(Self(level))
}
}
impl<T: ToPrimitive> ConfidenceLevel<T> {
pub fn to_f64(self) -> Option<ConfidenceLevel<f64>> {
self.0.to_f64().map(ConfidenceLevel)
}
pub fn to_f32(self) -> Option<ConfidenceLevel<f32>> {
self.0.to_f32().map(ConfidenceLevel)
}
}
impl<T: Float> From<ConfidenceLevel<T>> for SignificanceLevel<T> {
fn from(confidence_level: ConfidenceLevel<T>) -> Self {
SignificanceLevel::new(T::one() - confidence_level.0).unwrap() }
}