在编程中测试两个浮点数的相等性通常什么时候有意义?
IE
a == b
其中 a & b 都是浮点数。
我的天真印象是,人们总是会根据一些公差 epsilon 来测试差异。
我错了吗?在某些情况下测试浮点数的相等性是否有意义?
有来自野外的例子吗?即来自真正的代码库或 git 等应用程序。
PS。我隐含地假设在某些情况下在浮点数上使用相等运算符确实有意义;否则为什么大多数编程语言会允许它。
在编程中测试两个浮点数的相等性通常什么时候有意义?
IE
a == b
其中 a & b 都是浮点数。
我的天真印象是,人们总是会根据一些公差 epsilon 来测试差异。
我错了吗?在某些情况下测试浮点数的相等性是否有意义?
有来自野外的例子吗?即来自真正的代码库或 git 等应用程序。
PS。我隐含地假设在某些情况下在浮点数上使用相等运算符确实有意义;否则为什么大多数编程语言会允许它。
我的天真印象是,人们总是会根据一些公差 epsilon 来测试差异。
这个想法的一个不简单的实现可能应该利用相等比较运算符来处理IEEE 754标准考虑的重要特殊情况(无穷大、非规范化数字......)。
看看我应该如何进行浮点比较?:
...
if (a == b) // shortcut, handles infinities return true; if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) { // a or b is zero or both are extremely close to it // relative error is less meaningful here
...
有时确实有一个答案是正确的,而您想要完全相等。测试实现的正确性是一个很好的例子(即只有 40 亿个浮点数——所以测试它们!)。
可以的一个明显示例==
是何时a
和b
是相同的数字a=c; b=c
,例如,检查a
和b
是否以相同的方式初始化。当然,|a-b| < epsilon
也可以在这里工作。唯一的问题是,有多小epsilon
?
此外,a == b
会编译成一条指令,而|a-b| < epsilon
需要相当多的指令。
一个极端的例子:IBM 是第一家使用融合乘加指令构建处理器的公司。使用该指令,他们创建了一种非常快速的方法来根据 IEEE-754 标准计算平方根。对于单个输入值 1 ≤ x < 4,此方法失败:如果 x 是可表示为小于 4 的浮点数的最大数字,则结果将被错误地舍入。
所以在他们实现的某个地方,他们检查 x 是否等于那个特定的值。他们想要认识到这种价值,而不是其他任何价值。
我的天真印象是,人们总是会根据一些公差 epsilon 来测试差异。我错了吗?在某些情况下测试浮点数的相等性是否有意义?
没有独特的食谱。在本文中,有一个详尽的处理方法,您可以在其中找到包含技术和代码的完整答案。
总结起来主要有3种情况:
在某些情况下,您使用与容差进行比较的想法很好,但还有一种基于 Unit in the last place ( ULP ) 的技术,在文章中进行了描述
我隐含地假设在某些情况下在浮点数上使用相等运算符确实有意义;否则为什么大多数编程语言会允许它。
如上所述,在某些情况下您可以使用它,但请注意。例如 gcc 编译器有一个警告:
warning: comparing floating point with == or != is unsafe
我在这个论点之上添加了一些注意事项,它们与案例并不严格相关a == b
。
表达平等
考虑案例:
a + b == c
与a b c
花车。这就是我们正在编码的内容,但从数学的角度来看,我们正在做的事情更加迂腐:
通过这个操作,我们引入了一个可能的估计误差(给出界限):
所以在这种情况下使用==
起来就更加微妙了。
移植到不同的环境
当我们将代码移植到不同的环境(不同的机器)中时,我们可以获得一些不同的结果(例如尝试思考单元测试)。在使用的情况下==
也是微妙的。