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§
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.