在 Rust 中,对于两个浮点数和一个误差范围 delta 的断言,是否有一种首选的方法?
比如说...
let a = 3.0;
let b = 2.9999999999;
assert_eq!(a, b, 0.0001); // Imaginary syntax where a ~= b, within 0.0001
在 Rust 中,对于两个浮点数和一个误差范围 delta 的断言,是否有一种首选的方法?
比如说...
let a = 3.0;
let b = 2.9999999999;
assert_eq!(a, b, 0.0001); // Imaginary syntax where a ~= b, within 0.0001
还有一个approx crate,可以让您做这些事情:
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);
没有内置的宏可以实现这个功能,但你可以创建自己的宏。
以下是一种"绝对误差"版本的实现,参考了这篇文章。
macro_rules! assert_delta {
($x:expr, $y:expr, $d:expr) => {
if !($x - $y < $d || $y - $x < $d) { panic!(); }
},
}
具体来说,宏assert_delta
如果x
和y
的差以及y
和x
的差都大于或等于d
("delta"或"epsilon"值,即公差)时会引发 panic。
这种方法不好,因为选择一个固定的 epsilon 只是因为它“看起来很小”,但当被比较的数字非常小时,它实际上可能过大。比较会返回“true”来表示两个相当不同的数字相等。而当数字很大时,epsilon 可能比最小的舍入误差更小,使得比较总是返回“false”。
鉴于先前的实现在各种情况下都会出现问题,一般情况下,您不应该使用它。您可能需要实现一个更健壮的宏,例如检查“相对误差”的宏。
x=2.0, y=1.0, e=0.0001
。我们期望出现恐慌情况。x - y
大约是 1,不小于 epsilon,所以 or
的第一部分是 false,我们测试第二部分。or
的第二部分是 y - x
,大约是 -1,绝对小于 epsilon,所以条件返回 true。然后,我们否定条件,最终分支是 false,没有触发恐慌情况,尽管两个数字的绝对差大于 1。我有什么遗漏吗? - ggorlen还有另一个完整的组件assert_approx_eq解决了这个问题,比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