使用delta比较浮点数和双精度数的值?

4

据我了解,为避免固有的浮点误差问题,必须仔细比较浮点类型的值。通过使用误差阈值来比较值可以改善这种情况。

例如,以下解决方案比直接使用 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)) { ... }

上述解决方案来源于以下资源:在Java中直接比较两个float/double是否安全? 虽然我没有找到任何文献来证实这一点,但对我来说似乎同样适用于像x > y这样的比较。例如,如果xy基本相等,那么怎么可能一个大于另一个...
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;
}

我的假设正确吗?

2个回答

4

相等性测试正是使用delta(或epsilon)技术来处理浮点数的原因。

例如,我们希望将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);
}

非常感谢大家的帮助!这是一个非常好的答案,现在我明白为什么在这里也需要使用CompareAlmostEqual了。 - Lea Hayes

2

既然我们已经同意在这种情况下运算符=是通过CompareAlmostEqual完成的,那么在CompareGreaterOrEqual中使用它也是有道理的。

static bool CompareGreaterOrEqual(float x, float y, float delta) {
    return x >= y || CompareAlmostEqual(x, y, delta);
}

此外,虽然这些函数的使用方式高度取决于您的实际需求,但我建议将delta定义为常量变量,并在整个类中使用它,以确保使用相同的值(而不是作为参数传递)。


1
@MitchWheat - 实际上,看着我们回答下面的时间,我相信是胜利者,先生! - System Down

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接