C IEEE-Floats inf 等于 inf

C IEEE-Floats inf equal inf

在 C 中,在使用 IEEE-754 浮点数的实现中,当我比较两个为 NaN 的浮点数时,它 return 0 或 "false"。但是为什么两个都是 inf 的浮点数算作相等呢?

这个程序打印 "equal: ..."(至少在 Linux AMD64 和 gcc 下)并且在我看来它应该打印 "different: ...".

#include <stdio.h>
#include <stdlib.h>

int main(void)
  {
    volatile double a = 1e200; //use volatile to suppress compiler warnings
    volatile double b = 3e200;
    volatile double c = 1e200;
    double resA = a * c;  //resA and resB should by inf
    double resB = b * c;
    if (resA == resB)
      {   
        printf("equal: %e * %e = %e = %e = %e * %e\n",a,c,resA,resB,b,c);
      }   
    else
      {   
        printf("different: %e * %e = %e != %e = %e * %e\n", a, c, resA, resB, b, c);
      }   
    return EXIT_SUCCESS;
  }

另外一个例子,我认为inf和inf不一样的原因是:自然数和有理数的数,都是无限的,但不一样。

那么为什么 inf == inf?

无穷大比较相等,因为标准就是这么说的。来自 5.11 比较谓词的详细信息:

Infinite operands of the same sign shall compare equal.

inf==inf 出于与几乎所有浮点数比较等于自身相同的原因:因为它们相等。它们包含相同的符号、指数和尾数。

您可能会想到 NaN != NaN。但这是一个更重要的不变量的相对不重要的结果:NaN != x for any x。顾名思义,NaN 根本不是任何数字,因此不能比较等于任何东西,因为所讨论的比较是数字(因此 -0 == +0).

inf 与其他 inf 进行比较肯定是有意义的,因为在数学上下文中它们几乎肯定是不相等的。但是请记住,浮点数相等与绝对数学相等不是一回事。 0.1f * 10.0f != 1.0f,以及 1e100f + 1.0f == 1e100f。正如浮点数在不影响 as-good-as-possible 相等性的情况下逐渐下溢到非正规数一样,它们在不影响 as-good-as-possible 相等性的情况下溢出到无穷大。

如果你想要inf != inf,你可以模拟它:1e400 == 3e400求值为true,但是1e400 - 3e400 == 0求值为false,因为+inf + -inf的结果是NaN。 (可以说你可以说它的计算结果应该是 0,但这对任何人都没有好处。)

背景

在 C 中,根据 IEEE 754 二进制浮点标准(因此,如果您使用 floatdouble),您将获得一个可以比较的精确值与同一类型的另一个变量完全相同。嗯,这是真的,除非你的计算结果超出了可以表示的整数范围(即溢出)。

为什么无穷大==无穷大

resAresB IEEE-754 标准将无穷大和负无穷大的值分别调整为大于或小于根据标准可能表示的所有其他值(<= INFINITY == 0 11111111111 0000000000000000000000000000000000000000000000000000>= -INFINITY == 1 11111111111 0000000000000000000000000000000000000000000000000000), 除了 NaN,它不小于、等于或大于任何浮点值(甚至它本身)。请注意,无穷大及其负数在其符号、指数和尾数位中有明确的定义。

所以,resAresB 是无穷大,因为无穷大是明确定义和可重现的,所以 resA==resB。我相当确定这就是 isinf() 的实现方式。

为什么是NaN != NaN

但是,NaN 没有明确定义。一个 NaN 值有一个符号位 0,所有 1 的指数位(就像无穷大,它是负数),以及任何一组 non-zero 小数位(Source ).那么,如果它们的小数位无论如何都是任意的,您将如何区分一个 NaN 与另一个 NaN?好吧,当这个结构的两个浮点值相互比较时,标准不假设并且只是 returns false。

更多说明

因为无穷大是一个明确定义的值(来源,GNU C Manual):

Infinities propagate through calculations as one would expect

2 + ∞ = ∞

4 ÷ ∞ = 0

arctan (∞) = π/2.

但是,NaN 可能会也可能不会通过计算传播。当它出现时,它是一个 QNan(Quieting NaN,最高有效分数位设置)并且所有计算都将导致 NaN。如果不是,则为 SNan(信号 NaN,未设置最高有效分数位)并且所有计算都将导致错误。

算术系统有很多种。其中一些,包括通常在高中数学中涵盖的那些,例如实数,没有无穷大作为数字。其他的只有一个无穷大,例如 projectively extended real line. Others, such as the IEEE floating point arithmetic under discussion, and the extended real line,同时有正无穷大和负无穷大。

IEEE754 算术在许多方面不同于实数算术,但对于许多用途来说是一种有用的近似。

对 NaN 和无穷大的不同处理是有逻辑的。说正无穷大大于负无穷大和任何有限数是完全合理的。对 -1 的平方根说类似的话是不合理的。