Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

assert_eq! with floating point numbers and delta

Is there a preferred way to do an assert with two floating point numbers and a delta in Rust?

For example...

let a = 3.0;
let b = 2.9999999999;
assert_eq!(a, b, 0.0001); // Imaginary syntax where a ~= b, within 0.0001
like image 593
jocull Avatar asked Jun 15 '15 22:06

jocull


4 Answers

No. At the moment, you have to check the difference by yourself or use the float-cmp crate.

Also check out the f32 constants.

like image 55
eulerdisk Avatar answered Nov 08 '22 23:11

eulerdisk


There's no inbuilt macro for it, but you can create your own.

The following is an implementation of the "absolute error" version described in this article.

macro_rules! assert_delta {
    ($x:expr, $y:expr, $d:expr) => {
        if !($x - $y < $d || $y - $x < $d) { panic!(); }
    },
}

Specifically, the macro assert_delta panics if both the difference between x and y and y and x are greater or equal to d (the "delta" or "epsilon" value, i.e. the tolerance).

This is a bad way to do it because a fixed epsilon, chosen because it "looks small", could actually be way too large when the numbers being compared are very small as well. The comparison would return "true" for numbers that are quite different. And when the numbers are very large, the epsilon could end up being smaller than the smallest rounding error, so that the comparison always returns "false".

Given that the previous implementation breaks in various situations, in general, you should not use it. You may want to implement a more robust macro, e.g. the one that checks for a "relative error".

like image 37
user1535427 Avatar answered Nov 09 '22 00:11

user1535427


There's also the approx crate which lets you do things like these:

relative_eq!(1.0, 1.0, epsilon = f64::EPSILON);
relative_eq!(1.0, 1.0, max_relative = 1.0);
relative_eq!(1.0, 1.0, epsilon = f64::EPSILON, max_relative = 1.0);
like image 10
schmijos Avatar answered Nov 08 '22 23:11

schmijos


There is another complete crate assert_approx_eq solving this pain, better than float-cmp.

use assert_approx_eq::assert_approx_eq;

let a = 3f64;
let b = 4f64;

assert_approx_eq!(a, b); // panics
assert_approx_eq!(a, b, 2f64); //does not panic
assert_approx_eq!(a, b, 1e-3f64); // panics
like image 6
halfelf Avatar answered Nov 09 '22 00:11

halfelf