august 发表于 2008-4-12 15:16:42

数值问题

double h=0.1,r=0.1;
float k=r*(h*h);
int n=(1-0)/h;
int m=(0.005-0)/k;
printf("%d\n",m);

像这样一个程序,为什么它得出的结果会是4呢?

而像这样
double h,i;
int m;
h=0.005;
i=0.001;
m=h/i;
printf("%d\n",m);
为什么它的结果又是正确的呢?

rednaxela 发表于 2008-4-12 23:18:09

首先,这是C吧?C的话浮点数一般是用IEEE 754标准定义的单精度浮点数与双精度浮点数。
这些浮点数都是会损失精度的,在计算中会带来偏差。

0.005在双精度浮点数的编码是:
0 01111110111 0100011110101110000101000111101011100001010001111011
很明显不是一个准确值。

0.001在双精度浮点数的编码是:
0 01111110101 0000011000100100110111010010111100011010100111111100
很明显也不是一个准确值。

0.1在双精度浮点数编码下同样不是一个准确值。
0.1 * 0.1 * 0.1得到的双精度浮点数的编码是:
0 01111110101 0000011000100100110111010010111100011010100111111101
与上面的0.001比较:最后一位得到的结果不一样。

于是,如果用字面量的0.005除以0.001,有办法算出一个合理的值(在这里,得到的就会是5)。但如果这个近似0.001的值是算出来的,它的值很可能与字面量的0.001不一样。可以看到0.1*0.1*0.1得到的值大于0.001。所以0.005除以一个稍微比0.001大的值,得到的是4.9xxxx。被转换为整型之后,小数部分被抛弃,得到的就是4。

duzhi5368 发表于 2008-4-13 13:46:36

楼上解释的很清楚。 UP了

secondsen 发表于 2008-4-14 14:28:32

原来如此。。。书上写的会有误差,现在找到例子了

august 发表于 2008-4-16 16:24:20

那請問這個雙精度浮點數編碼是怎麼得到的?

rednaxela 发表于 2008-4-16 17:37:48

可以根据IEEE754的规范自己算……
想在C里看的话,如果是little-endian的平台,用printf("%x%x", myDouble)能看到一个十六进制的值,这个值的右边8位是高32位,左边的8位是低32位。左边不足32位的话前面都是0。
float的话直接printf("%x", myFloat)就是。
页: [1]
查看完整版本: 数值问题