AlmostEq

Trait AlmostEq 

Source
pub trait AlmostEq {
    // Required method
    fn almost_eq(&self, other: &Self, epsilon: f64) -> bool;
}
Expand description

A type of which two objects can be “almost equal” (i.e., have a distance less than ε).

§Examples

use std::collections::HashMap;

use l_system_fractals::num_validity::AlmostEq;

// Defined as (self - other).abs() < epsilon for f64 numbers

let a: f64 = 25.0;
let b: f64 = 24.99999;
assert!(a.almost_eq(&b, 0.0001));
assert!(!a.almost_eq(&b, 0.00000001));

assert_ne!((1.57_f64).sin(), 1.0); // off by about 3.17e-07

assert!((1.57_f64).sin().almost_eq(&1.0, 1e-06));
assert!(!(1.57_f64).sin().almost_eq(&1.0, 1e-09));

// Defined for HashMap<K, V> when V implements AlmostEq

let hm_1: HashMap<String, f64> = HashMap::from([
    ("alpha".into(), 10.001),
    ("beta".into(), -5.25001),
]);

let hm_2: HashMap<String, f64> = HashMap::from([
    ("alpha".into(), 9.999),
    ("beta".into(), -5.25002)
]);

let hm_3: HashMap<String, f64> = HashMap::from([
    ("alpha".into(), 10.001)
]);

let hm_4: HashMap<String, f64> = HashMap::from([
    ("alpha".into(), 10.001),
    ("beta".into(), -5.25001),
    ("gamma".into(), 3.0),
]);

assert!(hm_1.almost_eq(&hm_2, 0.01));
assert!(!hm_1.almost_eq(&hm_2, 0.001)); // "alpha" values too far apart
assert!(!hm_1.almost_eq(&hm_3, 0.01)); // hm_3 does not have key "beta"
assert!(!hm_1.almost_eq(&hm_4, 0.01)); // hm_1 does not have key "gamma"

// Defined for Vec<T> when T implements AlmostEq

let v_1: Vec<f64> = vec![3.0, 2.0, -5.0];
let v_2: Vec<f64> = vec![3.0, 2.0, -4.999];

assert!(v_1.almost_eq(&v_2, 0.002));
assert!(!v_1.almost_eq(&v_2, 0.0005));
use std::f64::consts::PI;

use l_system_fractals::num_validity::AlmostEq;

#[derive(Clone, Copy, Debug)]
struct Angle(f64);

impl Angle {
    fn reduce(&self) -> Self {
        Self(self.0.rem_euclid(2.0 * PI))
    }

    fn abs_diff(&self, other: &Self) -> Self {
        let diff = (self.0 - other.0).abs().rem_euclid(2.0 * PI);
        Self(diff.min(2.0 * PI - diff))
    }

    fn flip(&self) -> Self {
        Self(self.0 + PI).reduce()
    }
}

impl PartialEq for Angle {
    fn eq(&self, other: &Self) -> bool {
        self.reduce() == other.reduce()
    }
}

impl AlmostEq for Angle {
    fn almost_eq(&self, other: &Self, epsilon: f64) -> bool {
        self.abs_diff(&other).0 < epsilon
    }
}

let a = Angle(PI/4.0);
let b = Angle(9.0 * PI/4.0);
let c = Angle(PI * 0.249);

assert!(a.almost_eq(&b, 0.00001));
assert!(a.almost_eq(&c, 0.01));
assert!(!a.almost_eq(&c, 0.00001));

#[derive(Clone, Copy, Debug)]
struct PolarCoordinates {
    angle: Angle,
    radius: f64
}

impl PolarCoordinates {
    fn reduce(&self) -> Self {
        let neg_radius: bool = self.radius < 0.0;
        let radius: f64 = if neg_radius { - self.radius } else { self.radius };
        let angle: Angle = if neg_radius { self.angle.flip() } else {self.angle.reduce()};
        Self { angle, radius }
    }
}

impl PartialEq for PolarCoordinates {
    fn eq(&self, other: &Self) -> bool {
        self.radius == 0.0 && other.radius == 0.0 || {
            let s_red = self.reduce();
            let o_red = other.reduce();
            s_red.radius == o_red.radius && s_red.angle == o_red.angle
        }
    }
}

impl AlmostEq for PolarCoordinates {
    fn almost_eq(&self, other: &Self, epsilon: f64) -> bool {
        self.radius.abs() < epsilon && other.radius.abs() < epsilon || {
            let s_red = self.reduce();
            let o_red = other.reduce();
            s_red.radius.almost_eq(&o_red.radius, epsilon)
                && s_red.angle.almost_eq(&o_red.angle, epsilon)
        }
    }
}

let p1 = PolarCoordinates { angle: Angle(0.25 * PI), radius: 10.0 };
let p2 = PolarCoordinates { angle: Angle(2.24999 * PI), radius: 9.99999};

assert!(p1.almost_eq(&p2, 0.001));
assert!(!p1.almost_eq(&p2, 0.000000000000001));

let p3 = PolarCoordinates { angle: Angle(1.25 * PI), radius: 0.0005 };
let p4 = PolarCoordinates { angle: Angle(0.75 * PI), radius: 0.0005 };
assert!(p3.almost_eq(&p4, 0.001));
assert!(!p3.almost_eq(&p4, 0.00001));

Required Methods§

Source

fn almost_eq(&self, other: &Self, epsilon: f64) -> bool

Returns true if the distance between objects is less than epsilon.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl AlmostEq for f64

Source§

fn almost_eq(&self, other: &Self, epsilon: f64) -> bool

Source§

impl<K, V> AlmostEq for HashMap<K, V>
where V: AlmostEq, K: Eq + PartialEq + Hash,

Source§

fn almost_eq(&self, other: &Self, epsilon: f64) -> bool

Source§

impl<T> AlmostEq for Vec<T>
where T: AlmostEq,

Source§

fn almost_eq(&self, other: &Self, epsilon: f64) -> bool

Implementors§