使用相等性对浮点数进行比较的情况

Cases where floating-point numbers are comparable using equality

本文关键字:比较 情况 浮点数      更新时间:2023-10-16

最近我参与了一个关于浮点比较的讨论。我的观点是不要直接用==比较两个浮点数。

有人指出这是不正确的,在某些情况下,使用==是完全可以的。我可以想到典型的情况,我检查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)
    {
      ...
    
相关文章: