17

到目前为止,我已经看到很多关于浮点数相等的帖子。像“我们应该如何确定 x 和 y 是否相等?”这样的问题的标准答案。是

abs(x - y) < epsilon

其中 epsilon 是一个固定的小常数。这是因为“操作数”x 和 y 通常是一些涉及舍入误差的计算的结果,因此标准相等运算符 == 不是我们的意思,我们真正应该问的是 x 和 y 是否接近, 不相等。

现在,我觉得如果 x 与 y “几乎相等”,那么 x*10^20 也应该与 y*10^20 “几乎相等”,因为相对误差应该是相同的(但“相对“对什么?)。但是对于这些大数字,上述测试将失败,即该解决方案不会“扩展”。

你会如何处理这个问题?我们应该重新调整数字还是重新调整 epsilon?如何?(还是我的直觉错了?)

这是一个相关的问题,但我不喜欢它接受的答案,因为 reinterpret_cast 事情对我来说似乎有点棘手,我不明白发生了什么。请尝试提供一个简单的测试。

4

5 回答 5

20

这完全取决于具体的问题域。是的,在一般情况下使用相对误差会更正确,但它的效率可能会大大降低,因为它涉及额外的浮点除法。如果您知道问题中数字的大致比例,则可以使用绝对误差。

本页概述了一些比较浮点数的技术。它还讨论了许多重要问题,例如具有次正规、无穷大和 NaN 的问题。这是一本很棒的书,我强烈建议您通读一遍。

于 2008-11-30T05:22:08.373 回答
5

作为替代解决方案,为什么不直接对数字进行四舍五入或截断,然后进行直接比较?通过预先设置有效位数,您可以确定该范围内的准确性。

于 2008-11-30T06:53:42.747 回答
1

问题是,对于非常大的数字,与 epsilon 进行比较会失败。

也许更好(但更慢)的解决方案是使用除法,例如:

div(max(a, b), min(a, b)) < eps + 1

现在“错误”将是相对的。

于 2008-11-30T05:52:35.943 回答
0

使用相对误差至少不如使用绝对误差那么糟糕,但由于舍入问题,它对于接近零的值存在微妙的问题。一个远非完美但有些鲁棒的算法结合了绝对误差和相对误差方法:

boolean approxEqual(float a, float b, float absEps, float relEps) {
    // Absolute error check needed when comparing numbers near zero.
    float diff = abs(a - b);
    if (diff <= absEps) {
        return true;
    }

    // Symmetric relative error check without division.
    return (diff <= relEps * max(abs(a), abs(b)));
}

我从 Bruce Dawson 的优秀文章Comparing Floating Point Numbers, 2012 Edition中改编了这段代码,这是任何进行浮点比较的人的必读文章——这是一个非常复杂的主题,有很多陷阱。

于 2015-02-26T20:03:30.180 回答
0

大多数情况下,代码比较值是为了回答某种问题。例如:

  1. 如果我知道给定 X 值时函数返回什么,我可以假设如果给定 Y 它将返回相同的东西吗?

  2. 如果我有一种计算缓慢但准确的函数的方法,我愿意接受一些不准确以换取速度,并且我想测试一个似乎符合要求的候选函数,该函数的输出是否足够接近到已知准确的被认为是“正确的”。

为了回答第一个问题,理想情况下,代码应该对值进行逐位比较,除非一种语言支持 2009 年添加到 IEEE-754 的新运算符,其效率可能低于理想值。要回答第二个问题,应该定义所需的准确度并进行测试。

我认为通用方法没有太多优点,因为不同的应用程序对绝对和相对公差有不同的要求,这取决于测试应该回答的确切问题。

于 2015-02-27T23:00:47.293 回答