【问题标题】:Cases where floating-point numbers are comparable using equality [duplicate]浮点数使用等式可比较的情况[重复]
【发布时间】:2014-06-11 07:27:58
【问题描述】:

最近我开始讨论浮点比较。我的观点始终是不要直接使用== 比较两个浮点数。

有人指出这不是真的,在某些情况下使用== 是完全可以的。 我可以想到典型的情况,我检查 IEEE 754 文字,如 +-INF+-0,但除此之外,我想不出这样不会导致问题的情况。

所以我的问题是:使用== 进行浮点比较有效的情况是什么?

【问题讨论】:

  • 1. == 1.?使用== 检查NAN 不会让你走得太远。
  • 只要你真的想要相等,它就有效,而不是“足够接近以至于在精确算术下它可能相等”。 0 是这种情况的常见情况,但同样经常,您希望“足够接近 0”​​。
  • 我认为,如果您对相同的输入应用相同的计算*,则数字应该相同,因此在这种情况下,== 比较应该是有效的。 (*计算必须是确定性的)
  • @ShaZiv 我记得关于 fpu 和内存中变量的不同精度的一些事情。如果您计算一个值,将其存储回内存中,然后计算下一个(相同)值,从内存中加载回第一个结果然后进行比较,则检查可能会产生错误

标签: c++ floating-point


【解决方案1】:

双精度浮点表示(每个数字 64 位)精确到 -+2**53 (-+ 9,007,199,254,740,992) 的整数。如果您使用浮点数但从整数开始并使用它们进行整数计算并且您从未超过该限制,那么结果是精确的并且使用== 非常好。

通常可以精确表示的数字是 N/M,其中 N 是整数,M 是 2 的幂。因此,如果您只是进行涉及例如的计算1/4、1/2、3/4 和它们的整数倍也可以,直到达到非常大的乘数。

当您处理无法精确表示的数字(例如 0.1)时,近似值会导致我的结果令人惊讶。问题的一个来源是中间结果可能以更高的精度存储在临时变量中,因此公式的结果可能会有所不同,具体取决于您是否将其显式存储在内存中,并且它也可能根据优化级别而改变。

【讨论】:

  • 只是挑剔。示例中的“和它们的整数倍数”部分是多余的,因为您说N 是整数,因为整数的整数乘数也是整数。好吧,你本可以故意这么做的,但我觉得这很奇怪。我还认为该集合的等效定义是“任何二次幂的线性组合”(当然,除非数字太大或太小)。
【解决方案2】:

浮点数表示使用相应底数(通常为 2)的精确值。用相等来比较它们没有错。

二进制浮点数不能准确表示所有十进制值,即,对于大多数小数十进制值,二进制浮点将使用近似值。只要十进制数不超过std::numeric_limits<F>::digits10,则结果表示在系统内也是唯一标识的(对于某些十进​​制值,两个二进制表示之间有一个选择,在这种情况下,舍入方向应该选择正确的一个) .

使浮点数变得怪异的问题是,计算会导致值四舍五入,并且根据四舍五入发生的时间,据说精确的运算是不精确的,并且评估的顺序很重要。对四舍五入的值进行算术运算会相应地增加错误并产生与所获得的值不同的值,例如,通过从十进制值转换为二进制浮点。您可能不想对计算结果使用相等运算。

【讨论】:

    【解决方案3】:

    以下是一些有效使用浮点相等的示例:

    • 当函数记录为在某些情况下返回 HUGE_VAL 时,determining whether this happenedresult == HUGE_VAL

    • 确定双精度 d 是否包含可表示为 float 的数字:d == (double)(float)d。我实际上在我的日常工作中使用它,因为我使用双精度对来表示双精度值的间隔和浮点值的间隔,并且有些地方可以断言浮点间隔的边界是很好的浮动。

    • 判断浮点数y是否为NaNy == y

    • 确定浮点数 y is infinity or NaNy - y == 0.0y 的有限值使条件为真,NaN 和无穷大使其为假)。

    • 确定是否在浮点数的有效位中设置了位,如下例所示,取自this rant

      /* coef is a power of two plus one. */
      double t = coef * f;
      double o = f - t + t - f;
      if (o != 0)
      {
        ...
      

    【讨论】:

    • 你能用whole numbers like this question has评论这个案子吗
    • @ShafikYaghmour 不,生命太短暂了,强制性的“与 epsilon 比较”的糟糕答案已经被投票了 4 次。不值得。
    • 明白,感谢您的观看。
    • @PascalCuoq 当我将变量float x = 3.53.5 进行比较时,它返回相等/真,但当我比较float x = 3.4if(x == 3.4){ returns true} 时则不返回。如果我打印 x 和 3.4 的数据类型,我看到 x 是一个浮点数,但 3.4 被编译器视为双精度数,这看起来是后者评估为假的原因之一。但是,前一个如何评估为真呢?
    猜你喜欢
    • 1970-01-01
    • 2011-10-24
    • 2023-04-05
    • 2020-06-13
    • 2011-08-20
    • 1970-01-01
    • 2016-01-06
    相关资源
    最近更新 更多