混合int和double会在以下程序中产生奇怪的结果:
int main()
{
double x = 9.90, y = 10.0, z, w;
int ip, fp;
z = y - x;
ip = (int) z;
w = (z - ip)*100;
printf( "\nx = %f\ty = %f\tz = %f\tw = %f\n",
x, y, z, w );
printf("\nip = %d", ip); /* So far, so good */
fp = (int) w; /* Why does fp get 9 and not 10??? */
printf("\nfp = %d\n", fp);
return 0;
}
结果:
x = 9.900000 y = 10.000000 z = 0.100000 w = 10.000000
ip = 0
fp = 9 (Should be 10!)
使用MingGW(WinXP)e Clang(MacOSX)的结果是相同的。有人能解释这种奇怪的行为吗?
答案 0 :(得分:1)
问题在于你实际上是在尝试w = 0.1 * 100
,并且值不能用浮点精确表示(与1/3
无法精确表示的方式相同十进制)。
你得到的二进制0.1是这样的:
0.00011001100110011001100110011001100110011001100110011001...
最后4位数字永远重复。
虽然double没有无限的位数,所以它实际上是:
1.100110011001100110011001100110011001100110011001100110 * 2**(-4)
其中数字因不适合而被丢弃,从“01001001 ...”开始。因为丢弃的数字以0
开头,所以数字将向下舍入。这意味着您实际上最终会执行w = 0.9999999999 * 100
。
答案 1 :(得分:0)
错误的发生是因为double
无法完全保留值9.9
。它可以管理的最接近的是9.9000000000000003552713678800500929355621337890625
。因此,w
的值不是10
,而是9.99999999999996447286321199499070644378662109375
。
当您对printf使用%f
时,它会将您的值四舍五入到6位数。如果您将printf格式更改为%.60f
,则可以看到值的完整精度。