【问题标题】:Are there any floating-point comparison "anomalies"?是否有任何浮点比较“异常”?
【发布时间】:2010-09-13 08:53:30
【问题描述】:

如果我比较两个浮点数,是否存在a>=b 不等于b<=a!(a<b),或者a==b 不等于b==a!(a!=b) 的情况?

换句话说:比较总是“对称的”,这样我可以通过交换操作数和镜像运算符来获得相同的比较结果吗?并且它们是否总是“可否定”的,因此否定运算符(例如 ><=)相当于对结果应用逻辑非(!)?

【问题讨论】:

  • 我附加了第二段来澄清我的问题。根据公认的答案,由于 NaN,它们似乎是“对称的”但不是“可否定的”。

标签: comparison floating-point


【解决方案1】:

假设 IEEE-754 浮点:

  • a >= b 始终等同于 b <= a.*
  • a >= b 等效于 !(a < b),除非 ab 中的一个或两个为 NaN。
  • a == b 始终等同于 b == a.*
  • a == b 等效于 !(a != b),除非 ab 之一或两者为 NaN。

更一般地说:trichotomy 不适用于浮点数。相反,一个相关的属性持有 [IEEE-754 (1985) §5.7]:

可能有四种互斥关系:小于、等于、大于和无序。最后一种情况出现在至少一个操作数是 NaN 时。每个 NaN 都应与包括自身在内的所有内容进行无序比较。

请注意,这并不是真正的“异常”,而是将算术扩展为以尽可能与实际算术保持一致性的方式封闭的结果。

[*] 在抽象 IEEE-754 算法中为真。在实际使用中,某些编译器可能会在极少数情况下由于以扩展精度进行计算(MSVC,我在看你)而导致违反这一点。既然 Intel 架构上的大多数浮点计算都是在 SSE 而不是 x87 上完成的,这就不再是一个问题了(无论如何,从 IEEE-754 的角度来看,这始终是一个错误)。

【讨论】:

    【解决方案2】:

    在 Python 中,当涉及到 NaN 时,至少 a>=b 不等于 !(a<b)

    >>> a = float('nan')
    >>> b = 0
    >>> a >= b
    False
    >>> not (a < b)
    True
    

    我想大多数其他语言也是如此。

    另一件事可能会让您感到惊讶,NaN 甚至不等于它自己:

    >>> a == a
    False
    

    【讨论】:

    • +1:任何使用 IEEE 浮点的系统都会有这种奇怪的行为(或者它会因为产生这样的错误值而向你抛出异常;毕竟,它表明了算术在哪里出现了严重错误,比如0.0除以0.0的结果)。
    【解决方案3】:

    IEEE-754 浮点数集没有排序,因此您熟悉的一些关系代数和布尔代数不再成立。此异常是由 NaN 引起的,NaN 相对于集合中的任何其他值(包括其自身)没有排序,因此所有关系运算符都返回 false。这正是 Mark Byers 所展示的。

    如果您排除 NaN,那么您现在有一个有序集合,并且您提供的表达式将始终是等价的。这包括无穷大和负零。

    【讨论】:

      【解决方案4】:

      除了 NaN 问题,这有点类似于 SQL 中的 NULL 和 SAS 和其他统计包中的缺失值,总是存在浮点运算准确性的问题。无法准确表示小数部分(例如 1/3)和无理数中的重复值。由于精度的有限限制,浮点算术经常会截断结果。对浮点值进行的运算越多,潜入的误差就越大。

      比较浮点值最有用的方法可能是使用算法:

      1. 如果任一值为 NaN,则所有比较都是错误的,除非您明确检查 NaN。
      2. 如果两个数字之间的差异在某个“模糊因子”内,则认为它们相等。模糊因子是您对累积的数学不精确度的容忍度。
      3. 模糊相等比较后,再比较小于或大于。

      请注意,比较“=" 与比较精确相等的风险相同。

      【讨论】:

        【解决方案5】:

        不,不适用于任何合理的浮点实现:基本对称和布尔逻辑适用。但是,equality in floating point numbers 在其他方面很棘手。在极少数情况下测试a==b 的浮点数是合理的做法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-09-12
          • 1970-01-01
          • 2013-08-20
          • 2011-10-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多