Home > other >  Rust: Generic 'within epsilon' trait for Nums
Rust: Generic 'within epsilon' trait for Nums

Time:06-20

I'd like to be able to create a function which I can call on Floats or Complex types which returns true when they are within a specified distance from each other.

This is the closest I got, which of course does not cover Compelx numbers:

fn eq_within_epsilon<F: Float>(a: F, b:F, eps: F) -> bool {
    F::abs(a - b) < eps
}

I attempted to expand the definition abit, like this, to cover all Num:

trait EqWithinEpsilon {
    fn eq_within_epsilon<T: Num>(a: T, b:T, eps: T) -> bool;
}

impl EqWithinEpsilon for dyn Float {
    fn eq_within_epsilon<T: Num>(a: T, b: T, eps: T) -> bool {
        T::abs(a - b) < eps
    }
}

but I get the error:

the trait cannot be made into an object because it uses `Self` as a type parameter

Is there any way I can do this.

And just in case it comes up, I am using the following crates:

num-complex = "0.4.0"
num-traits = "0.2.15"

CodePudding user response:

Implementing a method for dyn Trait is almost never what you want. It doesn't implement the method for all types that implement the trait, but rather on the trait itself.

Usually you would need a blanket implementation (impl<F: Float> EqWithEpsilon for F), but in this case it will not work. You need a trait that is common to both Complex and floats. You can write your own:

trait ComplexFloat: Num {
    type Real: Float;
    fn abs(self) -> Self::Real;
}

// We cannot use a blanket implementation because of coherence.
impl ComplexFloat for f32 {
    type Real = Self;
    fn abs(self) -> Self::Real { self.abs() }
}
impl ComplexFloat for f64 {
    type Real = Self;
    fn abs(self) -> Self::Real { self.abs() }
}

impl<F: Float> ComplexFloat for Complex<F> {
    type Real = F;
    fn abs(self) -> Self::Real { self.norm() }
}

fn eq_within_epsilon<F: ComplexFloat>(a: F, b: F, eps: F::Real) -> bool {
    F::abs(a - b) < eps
}

If you use the very last version of num_traits, 0.4.2 (it wasn't even released to the playground yet, at the time of writing), you can use a ready trait: ComplexFloat.

  • Related