平等测试和机器的准确性

时间:2014-05-14 06:43:27

标签: c

我在第174页,C-Al Kelley,Ira Pohl的书上找到了这段代码。

int main()
{
 int cnt=0; double sum=0.0,x; 
 for( x=0.0 ;x!= 9.9 ;x+=0.1)
 {
   sum=sum +x;
   printf("cnt = %5d\n",cnt++);
 }
 return 0;

}

并且它成了一个无限循环,正如书中所说的那样。它没有提到确切的原因,只是说它与机器的准确性有关。

我修改了代码以检查是否      X = 9.9 将永远变为现实,即通过添加以下行来获得9.9

 diff=x-9.9;
 printf("cnt =10%d  \a x =%10.10lf  dif=%10.10lf \n",++cnt,x,diff);

我在输出中得到以下几行

 cnt =1098   x =9.7000000000  dif=-0.2000000000 
 cnt =1099   x =9.8000000000  dif=-0.1000000000 
 cnt =10100   x =9.9000000000  dif=-0.0000000000 
 cnt =10101   x =10.0000000000  dif=0.1000000000 
 cnt =10102   x =10.1000000000  dif=0.2000000000 

如果x正好达到9.9的值,为什么它仍然是无限循环?

4 个答案:

答案 0 :(得分:1)

问题是大多数浮点实现都基于IEEE 754.请参阅http://en.wikipedia.org/wiki/IEEE_floating_point

问题在于,数字是用基数2(二进制格式)构建的。

数字9.9永远不能用基数2来构建。

David Goldberg撰写的“数值计算指南”对此有一个确切的陈述:

  

已经提出了几种不同的实数表示,   但到目前为止,使用最广泛的是浮点表示法。   浮点表示有一个基数b(总是假设为   是偶数)和精度p。如果b = 10且p = 3,那么数字0.1是   表示为1.00×10 ^ -1。如果b = 2且p = 24,则为小数   数字0.1不能精确表示,但大约是   1.10011001100110011001101×2 ^ -4。

答案 1 :(得分:1)

您只是打印数字的准确性太差,不会发现它不准确。尝试这样的事情:

#include <stdio.h>

int main()
{
  double d = 9.9;

  if(d == 9.9)
  {
    printf("Equal!");
  }
  else
  {
    printf("Not equal! %.20f", d);
  }
}

我机器上的输出:

Not equal! 9.90000000000000035527

本书可能会试图教你永远不要使用==或!=运算符来比较浮点变量。同样出于同样的原因,永远不要使用浮点数作为循环迭代器。

答案 2 :(得分:0)

您可以放心地假设两个浮点数从不等于'完全'(除非一个是另一个的副本)。

答案 3 :(得分:0)

计算机适用于二进制和浮点,换句话说就是基数2.就像基数10一样,基数2具有无法构建的数字。例如,尝试在基数10中写出分数10/3。最终会得到无限的3。在Binary中,你甚至不能用二进制写0.1(十进制),你也会得到一个循环模式0.0001100110011 ......(二进制)。

此视频可以更好地解释http://www.youtube.com/watch?v=PZRI1IfStY0