2010-03-24 162 views
2

我尝试下面的代码片段输出是令人惊讶的我:打印双变量内容

#include <stdio.h> 
#include <math.h> 

int main() 
{ 
      double num; 
      unsigned char ch; 

      ch = 19; 
      num = 1.0E+20 ; 
      num += ch * 1.0E+18; 
      printf("E18 = %lf \n",num); 
      printf("E18 = %e \n",num); 

      num = 11.0E+21 ; 
      num += ch * 1.0E+19; 
      printf("E19 = %lf <------\n",num); 
      printf("E19 = %e <------\n",num); 

      num = 11.0E+22 ; 
      num += ch * 1.0E+20; 
      printf("E20 = %lf\n",num); 
      printf("E20 = %e\n",num); 

      num = 11.0E+23 ; 
      num += ch * 1.0E+21; 
      printf("E21 = %lf\n",num); 
      printf("E21 = %e\n",num); 

      num = 11.0E+24 ; 
      num += ch * 1.0E+22; 
      printf("E22 = %lf <------\n",num); 
      printf("E22 = %e <------\n",num); 
    return 0; 
} 

程序的输出:

E18 = 119000000000000000000.000000 
E18 = 1.190000e+20 
E19 = 11190000000000000524288.000000 <------ 
E19 = 1.119000e+22 <------ 
E20 = 111900000000000001048576.000000 
E20 = 1.119000e+23 
E21 = 1119000000000000044040192.000000 
E21 = 1.119000e+24 
E22 = 11189999999999999366660096.000000 <------ 
E22 = 1.119000e+25 <------ 

为什么印刷,而在指数形成了OK时损坏的数据

回答

3

数据未损坏;这就是浮点数值在当今计算机中的工作原理。将浮点数看作固定的数字位数(尾数),另一个数字表示小数点应该放在哪里(指数)。对于更长,更准确的故事,Wikipedia is a good start

由于尾数位数是固定的,它不能代表你在这里要求的微小部分。此外,因为它都是二进制的,所以十进制数不能总是精确表示。

指数表示法简单地将最后几位数字舍去,其中数字已知是不准确的,因此是您的结果。

0

浮点数据类型使用有限数量的位来表示特定的数字范围。但是,任何两个实数m和n之间可以有无数个值。所以,你牺牲精确度。

由于并非所有数字都正在打印,所以它在指数形式中看起来没问题。

作为测试,尝试用大约10位小数打印值0.2,你会看到存储的值更像是0.1999999 ....

0

你看到在浮点固有的不精确性。

某些printf转换可保证产生足够的有效数字来唯一标识正在打印的数字。这意味着如果有任何不准确的地方,你会看到它。相反,默认%e/%f表示法通过四舍五入来隐藏不精确性。

据我所知,%a(十六进制浮点数)是实现这个的唯一方法。据the POSIX spec%lf被定义为做同样的事情作为%f,即,

l(ELL)...有没有影响随后的一个,A,E,E,F,F,G,或G转换说明符。

所以这在技术上是标准库中的一个错误。