据我所知,必须仔细比较浮点类型的值,以避免固有浮点错误的问题。这可以通过将值与错误阈值进行比较来改进。
例如,以下解决方案比直接x == y
测试更有用:
static float CompareRelativeError(float x, float y) {
return Math.Abs(x - y) / Math.Max(Math.Abs(x), Math.Abs(y));
}
static bool CompareAlmostEqual(float x, float y, float delta) {
return x == y || CompareRelativeError(x, y) < delta;
}
// apologies if this is a poor example
if (CompareAlmostEqual(1f/10f, 0.1f)) { ... }
以上解决方案源自以下资源: Is it safe when compare 2 float/double directly in Java?
虽然我还没有找到任何文献来证实这一点,但对我来说似乎同样必须适用于x > y
这样的比较。例如,如果x
和y
基本相同,那么一个人如何能够比另一个更大......
static bool CompareGreater(float x, float y, float delta) {
return x > y && !CompareAlmostEqual(x, y, delta);
}
因此以下内容适用于x >= y
:
static bool CompareGreaterOrEqual(float x, float y) {
return x >= y;
}
我的假设是否正确?
答案 0 :(得分:4)
等式测试正是delta(或epsilon)技术用于浮点值的原因。
e.g。我们希望3等于2.999999 ...到某种精确度。
因此定义为:
时,CompareGreaterOrEqual
方法不够用
static bool CompareGreaterOrEqual(float x, float y) {
return x >= y;
}
应该是:
static bool CompareGreaterOrEqual(float x, float y, float delta) {
return x >= y || CompareAlmostEqual(x, y, delta);
}
注意:第一次测试中的x >= y
可能只是x > y
,因为delta比较会处理相等:
static bool CompareGreaterOrEqual(float x, float y, float delta) {
return x > y || CompareAlmostEqual(x, y, delta);
}
答案 1 :(得分:2)
由于我们已经同意在这种情况下运算符=
是通过CompareAlmostEqual
完成的,因此在CompareGreaterOrEqual
中使用它也是有意义的。
static bool CompareGreaterOrEqual(float x, float y, float delta) {
return x >= y || CompareAlmostEqual(x, y, delta);
}
此外,虽然它在很大程度上取决于你如何利用这些函数,但我也会使delta
成为整个类中使用的常量变量,以确保使用相同的值(而不是将其作为参数传递) )。