关于浮点:C IEEE-Floats inf等于inf

C IEEE-Floats inf equal inf

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

这个程序打印"相等:......"(至少在Linux AMD64下使用gcc),在我看来它应该打印"不同:......"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#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
"
,a,c,resA,resB,b,c);
      }  
    else
      {  
        printf("different: %e * %e = %e != %e = %e * %e
"
, 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对于任何x。顾名思义,NaN根本不是任何数字,因此无法比较等于任何数字,因为所讨论的比较是数字比较(因此-0 == +0)。

inf与其他inf进行比较不等于肯定会有一些意义,因为在数学语境中它们几乎肯定是不相等的。但请记住,浮点平等与绝对数学平等不同; 0.1f * 10.0f != 1.0f1e100f + 1.0f == 1e100f。正如浮点数逐渐下降到非正规数而不会损害尽可能好的平等,所以它们会溢出到无穷大而不会损害尽可能好的平等。

如果需要inf != inf,则可以模拟它:1e400 == 3e400计算结果为true,但1e400 - 3e400 == 0计算结果为false,因为+inf + -inf的结果为NaN。 (可以说你可以说它应该评估为0,但这对任何人都没有兴趣。)


背景

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

为什么Infinity ==无限

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

因此,resAresB是无穷大的,因为无穷大是明确定义和可再现的,resA==resB。我很确定这是isinf()的实现方式。

为什么NaN!= NaN

但是,没有明确定义NaN。 NaN值的符号位为0,所有1的指数位(就像无穷大而且它是负的),以及任何非零分数位(源)。那么,如果他们的分数位是任意的,你怎么能告诉另一个NaN呢?好吧,标准不假设并且当这个结构的两个浮点值相互比较时简单地返回false。

更多解释

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

Infinities propagate through calculations as one would expect

2 + ∞ = ∞

4 ÷ ∞ = 0

arctan (∞) = π/2.

但是,NaN可能通过计算传播也可能不通过传播传播。当它发生时,它是一个QNan(Quieting NaN,最重要的分数位集),所有计算都将导致NaN。当它没有时,它是一个SNan(信令NaN,未设置的最重要的分数位),并且所有计算都将导致错误。


有许多算术系统。 其中一些,包括高中数学中通常涵盖的那些,例如实数,没有无穷大的数字。 其他人有一个无穷大,例如投射扩展的实线。 其他的,例如正在讨论的IEEE浮点运算,以及扩展的实线,具有正无穷大和负无穷大。

IEEE754算法在许多方面与实数算术不同,但对于许多目的而言是有用的近似。

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