使用相等性对浮点数进行比较的情况
Cases where floating-point numbers are comparable using equality
最近我参与了一个关于浮点比较的讨论。我的观点是不要直接用==
比较两个浮点数。
有人指出这是不正确的,在某些情况下,使用==
是完全可以的。我可以想到典型的情况,我检查IEEE 754字面量,如+-INF
或+-0
,但除此之外,我想不出一个不会导致问题的情况。
所以我的问题是:使用==
进行浮点比较是有效的情况是什么?
对于-+2**53(-+ 9,007,199,254,740,992)以内的整数,双精度浮点表示(每个数字64位)是精确的。如果你使用的是浮点数,但从整数开始,用它们进行整数计算,并且你从未超过这个限制,那么结果是精确的,使用==
是完全可以的。
通常可以精确表示的数是N/M,其中N是整数,M是2的幂。因此,如果你只是在计算1/4,1/2,3/4和它们的整数倍,你也可以,直到你遇到非常大的乘数。
相反,当你处理不能精确表示的数字(例如0.1)时,近似值将我的结果引入了令人惊讶的结果。问题的一个来源是,中间结果可能以更高的精度存储在临时中,因此公式的结果可能会因是否显式地将其存储在内存中而不同,并且也可能因优化级别而改变。
浮点数使用相应的基数表示精确值(通常为2),使用相等来比较它们并没有错。
二进制浮点数不能精确地表示所有的十进制值,也就是说,对于大多数小数十进制值,二进制浮点数将使用近似值。只要十进制数不超过std::numeric_limits<F>::digits10
,结果表示也是唯一标识的,在一个系统中(对于某些十进制值,有两个二进制表示之间的选择,在这种情况下,舍入方向应该选择正确的一个)。
使浮点数变得有点奇怪的问题是计算导致值的舍入,并且取决于舍入发生的时间,假设精确操作是不精确的,并且计算顺序很重要。对四舍五入值进行算术运算将相应地增加误差,并产生与所获得的值不同的值,例如,将十进制值转换为二进制浮点数。您可能不希望对计算结果使用相等运算。
下面是一些有效使用浮点数相等的例子:
-
当一个函数在文档中被记录为在某些情况下返回
HUGE_VAL
时,确定result == HUGE_VAL
是否发生了这种情况。 -
确定双精度
d
是否包含可表示为float
:d == (double)(float)d
的数字。我实际上在我的日常工作中使用它,因为我使用双精度对来表示双精度值的间隔和浮点值的间隔,并且在某些点上能够断言浮点数间隔的界限是浮点数是很好的。 -
判断浮点数
y
是否为NaN
:y == y
. -
确定浮点数
y
是否为无穷大或NaN与y - y == 0.0
(y
的有限值使条件为真,NaN
和无穷大使条件为假)。 -
决定一个位是否被设置在浮点数的有效位上,如下面的例子所示,取自这个rant。
/* coef is a power of two plus one. */ double t = coef * f; double o = f - t + t - f; if (o != 0) { ...
- C++复杂情况的比较器通过参数问题
- 在单元测试中,如何在不使用 operator== 的情况下比较两个对象,这可能会错过新成员?
- 需要使用 3 个变量在没有函数的情况下进行比较
- 编译器在这里做什么,允许在很少进行实际比较的情况下比较许多值
- 如果堆栈在数字较低的地址增长,为什么指针比较会逆转这种情况?
- 如何在不复制的情况下比较字符串的一部分?
- 在这种情况下,可以比较无效的迭代器
- 在没有比较运算符的情况下查找 2 个数字之间的最小值
- 为什么在浮点比较中,最后一个小数位数为5的浮点值能给出正确的输出,而在其他情况下却不是
- 如何在不使用 lambda 表达式的情况下实现特定的比较器
- 在给定迭代器的情况下检索容器的比较函数
- 动态C++与其他语言的比较 - 在不知道类型的情况下无法在对象上调用方法
- 为什么我不能在没有常量的情况下定义比较
- 如何在不使用 strcmp 和方括号的情况下比较字符串
- 在这种情况下比较 std::vector 或 std::set 以获得时间复杂度 - 更有效率
- 使用自己的比较器运算符()进行映射<>。在找不到 KEY 的情况下给出错误
- 在哪种情况下,我可以在C++中使用==直接比较两个浮点变量
- 在没有公共getter的情况下,比较两个相同类型的对象是否相等
- 如何在不考虑类型顺序的情况下比较相同类型的元组
- 我可以使用' == '来比较两个向量吗?我试过了,似乎工作正常。但我不知道它是否适用于更复杂的情况