float_plus 2.0.1

Additional features for float values
Documentation
use cast::f32;
use cast::f64;
use num_traits::abs;

pub trait NApproxEq {
    fn nae(&self, other: Self, decimals: u8) -> bool;
}

impl NApproxEq for f64 {
    fn nae(&self, other: Self, decimals: u8) -> bool {
        let decimals = f64(decimals);
        let max_diff = 10.0_f64.powf(-decimals);

        let nae = abs(self - other) > max_diff;
        nae
    }
}

impl NApproxEq for Option<f64> {
    fn nae(&self, other: Self, decimals: u8) -> bool {
        if self.is_none() && other.is_none() {
            return false;
        }

        if self.is_some() && other.is_some() {
            let Some(first) = self else {
                return true;
            };
            let Some(second) = other else {
                return true;
            };

            let decimals = f64(decimals);
            let max_diff = 10.0_f64.powf(-decimals);

            let nae = abs(first - second) > max_diff;

            return nae;
        }

        true
    }
}

impl<E> NApproxEq for Result<f64, E> {
    fn nae(&self, other: Self, decimals: u8) -> bool {
        if self.is_err() && other.is_err() {
            return false;
        }

        if self.is_ok() && other.is_ok() {
            let Ok(first) = self else {
                return true;
            };
            let Ok(second) = other else {
                return true;
            };

            let decimals = f64(decimals);
            let max_diff = 10.0_f64.powf(-decimals);

            let nae = abs(first - second) > max_diff;

            return nae;
        }

        true
    }
}

impl NApproxEq for f32 {
    fn nae(&self, other: Self, decimals: u8) -> bool {
        let decimals = f32(decimals);
        let max_diff = 10.0_f32.powf(-decimals);

        let nae = abs(self - other) > max_diff;

        nae
    }
}

impl NApproxEq for Option<f32> {
    fn nae(&self, other: Self, decimals: u8) -> bool {
        if self.is_none() && other.is_none() {
            return false;
        }

        if self.is_some() && other.is_some() {
            let first = self.unwrap();
            let second = other.unwrap();

            let decimals = f32(decimals);
            let max_diff = 10.0_f32.powf(-decimals);

            let nae = abs(first - second) > max_diff;

            return nae;
        }

        true
    }
}

impl<E> NApproxEq for Result<f32, E> {
    fn nae(&self, other: Self, decimals: u8) -> bool {
        if self.is_err() && other.is_err() {
            return false;
        }

        if self.is_ok() && other.is_ok() {
            let Ok(first) = self else {
                return true;
            };
            let Ok(second) = other else {
                return true;
            };

            let decimals = f32(decimals);
            let max_diff = 10.0_f32.powf(-decimals);

            let nae = abs(first - second) > max_diff;

            return nae;
        }

        true
    }
}

#[cfg(test)]
mod tests {
    use anyhow::Error;

    use crate::decimals::not_approx_eq_dec::NApproxEq;

    #[test]
    fn nae_f64() {
        let a = 100.123_456_789_f64;
        let b = 100.123_456_712_f64;

        assert!(!a.nae(b, 7));
        assert!(a.nae(b, 8));
    }

    #[test]
    fn nae_option_f64() {
        let a = Some(100.123_456_789_f64);
        let b = Some(100.123_456_712_f64);
        assert!(!a.nae(b, 7));
        assert!(a.nae(b, 8));

        let a = None::<f64>;
        let b = None;
        assert!(!a.nae(b, 0));

        let a = Some(100.123_456_789_f64);
        let b = None;
        assert!(a.nae(b, 0));

        let a = None;
        let b = Some(100.123_456_789_f64);
        assert!(a.nae(b, 0));
    }

    #[test]
    fn nae_result_f64() {
        let a = Ok::<f64, Error>(100.123_456_789_f64);
        let b = Ok::<f64, Error>(100.123_456_712_f64);
        assert!(!a.nae(b, 7));

        let a = Ok::<f64, Error>(100.123_456_789_f64);
        let b = Ok::<f64, Error>(100.123_456_712_f64);
        assert!(a.nae(b, 8));

        let a = Err::<f64, Error>(Error::msg(""));
        let b = Err(Error::msg(""));
        assert!(!a.nae(b, 0));

        let a = Ok::<f64, Error>(100.123_456_789_f64);
        let b = Err(Error::msg(""));
        assert!(a.nae(b, 0));

        let a = Err(Error::msg(""));
        let b = Ok::<f64, Error>(100.123_456_789_f64);
        assert!(a.nae(b, 0));
    }

    #[test]
    fn nae_f32() {
        let a = 100.123_45_f32;
        let b = 100.123_31_f32;

        assert!(!a.nae(b, 3));
        assert!(a.nae(b, 4));
    }

    #[test]
    fn nae_option_f32() {
        let a = Some(100.678_9_f32);
        let b = Some(100.671_2_f32);
        assert!(!a.nae(b, 2));
        assert!(a.nae(b, 3));

        let a = None::<f32>;
        let b = None;
        assert!(!a.nae(b, 0));

        let a = Some(100.678_9_f32);
        let b = None;
        assert!(a.nae(b, 0));

        let a = None;
        let b = Some(100.671_2_f32);
        assert!(a.nae(b, 0));
    }

    #[test]
    fn nae_result_f32() {
        let a = Ok::<f32, Error>(100.456_78_f32);
        let b = Ok::<f32, Error>(100.456_71_f32);
        assert!(!a.nae(b, 4));

        let a = Ok::<f32, Error>(100.456_78_f32);
        let b = Ok::<f32, Error>(100.456_71_f32);
        assert!(a.nae(b, 5));

        let a = Err::<f32, Error>(Error::msg(""));
        let b = Err(Error::msg(""));
        assert!(!a.nae(b, 0));

        let a = Ok::<f32, Error>(100.456_78_f32);
        let b = Err(Error::msg(""));
        assert!(a.nae(b, 0));

        let a = Err(Error::msg(""));
        let b = Ok::<f32, Error>(100.456_78_f32);
        assert!(a.nae(b, 0));
    }
}