对于以下循环,我希望输出为sum = 20e6
,但输出为sum = 1.67772e+07
。
float sum=0.0f;
for(i=0;i<20e6;i++)
sum = sum + 1.0f;
printf("sum = %g\n", sum);
问题1:为什么sum
浮动无法保存大于1.67772e07
的值?
问题2:如果我将循环中的语句更改为sum = sum + 1.001f;
,则sum的最终值为2.32229e+07
。为什么这个和的值有差异?
问题3:我们是否可以在上面的循环中控制此行为,以便我们可以将float用于大于1.67772e07
的值,同时仍然增加1.0f?
答案 0 :(得分:8)
在某些时候,与x + 1.0f
最接近的可表示值是x
本身。达到该点后,由于此舍入错误,您的循环不会导致sum
进一步增加。
作为一个例子,您可以使用具有固定数量的有效数字的科学记数法来观察此效果。例如,有4位有效数字:
0 = 0.000e0
1 = 1.000e0
2 = 2.000e0
3 = 3.000e0
...
9 = 9.000e0
10 = 1.000e1
11 = 1.100e1
...
99 = 9.900e1
100 = 1.000e2
101 = 1.010e2
...
999 = 9.990e2
1000 = 1.000e3
1001 = 1.001e3
...
9999 = 9.999e3
10000 = 1.000e4
如果您再添加一个,则应获得1.0001e4
,但由于仅保留了4位有效数字,因此存储的值为1.000e4
,例如10000 + 1 = 10000在这个系统中,继续增加只是重复这个计算而不改变结果。
您的代码的工作原理完全相同,只是float
使用二进制浮点数,而不是科学数字符号的小数。但是有效二进制数字的数量仍然是有限的,当再添加一个数字并不会改变其中一个有效数字时,sum
就会停止增加。
它有点复杂,因为使用二进制,&#34;正确&#34;结果位于两个可表示的数字之间,因此舍入可以向下或向上,在这种情况下,您要求添加1,但实际上得到的结果为2。在任何情况下,一旦可表示值之间的距离变为4,尝试添加一个将无效。