use num_traits::{Num, NumCast};
pub fn approx_eq<T>(a: T, b: T, tol: f64)
where
T: Num + NumCast + Copy,
{
let aa = a.to_f64().unwrap();
let bb = b.to_f64().unwrap();
if aa.is_nan() {
panic!("the first number is NaN");
}
if bb.is_nan() {
panic!("the second number is NaN");
}
if aa.is_infinite() {
panic!("the first number is Inf");
}
if bb.is_infinite() {
panic!("the second number is Inf");
}
let diff = f64::abs(aa - bb);
if diff > tol {
panic!("numbers are not approximately equal. diff = {:?}", diff);
}
}
#[cfg(test)]
mod tests {
use super::approx_eq;
#[test]
#[should_panic(expected = "the first number is NaN")]
fn panics_on_nan_1() {
approx_eq(f64::NAN, 2.5, 1e-1);
}
#[test]
#[should_panic(expected = "the second number is NaN")]
fn panics_on_nan_2() {
approx_eq(2.5, f64::NAN, 1e-1);
}
#[test]
#[should_panic(expected = "the first number is Inf")]
fn panics_on_inf_1() {
approx_eq(f64::INFINITY, 2.5, 1e-1);
}
#[test]
#[should_panic(expected = "the second number is Inf")]
fn panics_on_inf_2() {
approx_eq(2.5, f64::INFINITY, 1e-1);
}
#[test]
#[should_panic(expected = "the first number is Inf")]
fn panics_on_inf_3() {
approx_eq(f64::NEG_INFINITY, 2.5, 1e-1);
}
#[test]
#[should_panic(expected = "the second number is Inf")]
fn panics_on_inf_4() {
approx_eq(2.5, f64::NEG_INFINITY, 1e-1);
}
#[test]
#[should_panic(expected = "numbers are not approximately equal. diff = 0.5")]
fn panics_on_different_values() {
approx_eq(2.0, 2.5, 1e-1);
}
#[test]
#[should_panic(expected = "numbers are not approximately equal. diff = 0.5")]
fn panics_on_different_values_f32() {
approx_eq(2f32, 2.5f32, 1e-1);
}
#[test]
fn accepts_approx_equal_values() {
let a = 2.0;
let b = 2.02;
let tol = 0.03;
approx_eq(a, b, tol);
}
#[test]
fn accepts_approx_equal_values_f32() {
approx_eq(2f32, 2.02f32, 0.03);
}
}