c中%f说明符的不可预知行为

时间:2013-09-06 05:12:13

标签: c++ c

使用以下代码:

float f = 23.456;
printf("%f", f);

f的不同值的输出为:

 Value       Output
---------    --------       
f = 23.456   23.455999 
f = 23.956   23.955999
f = 23.947   23.947001
f = 23.656   23.656000

为什么获得的值不可预测或存在模式?

3 个答案:

答案 0 :(得分:7)

这属于每个程序员应该知道浮点数的类别。浮点的工作方式意味着某些数字在浮点中不能完全表示。解释这个的最简单方法是要求你将值1/3写为十进制数。你很开心,但最终你最终没纸了。这样做的原因是,在十进制表示法中,数字1/3是无限长的,所以在一个使用十进制表示法来存储数字的合理编码系统中,它可以存在多长时间。

浮点做同样的事情,但使用基数2.这意味着我们看起来非常简单的数字,例如1/10或0.1,变为无限递归。当您打印数字时,这会导致舍入错误,因为您存储的数字不是您为编译器提供的数字,因为无法存储该数字。

关于此的规范性论文是http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html,这是一本很重要的读物,但解释了所有这些以及更多内容。

答案 1 :(得分:4)

这是因为C使用IEEE 754 32-bit floating point format来存储浮点数。您拥有的尾数以二进制形式转换,并存储在float变量所需的低位23位4字节空间中。有时它可以完全转换为精确的二进制,有时它可能没有完全转换,因此存储了截断形式的数字,从内存中读取时,计算结果略有不同。

此行为类似于数学,您使用1/3的值为0.33或0.333,具体取决于您的精确度要求。

尝试使用:
f = 0.25;或,
f = -15.625;或者,任何十进制值都可以完全转换为二进制,您将获得正确的结果。

答案 2 :(得分:2)

使用floatdouble,您有一定的位数来表示计算机中的号码x。对于float,它通常是32位,double有64位。

结果呢?您只能在float中存储2 ^ 32个不同的数字,在double中存储2 ^ 64个数字。由于存在无限量的“其他”数字,这意味着这些数字无法表示。但人们仍然希望使用这些数字(关于数字不可用的编译器错误会很奇怪,不是吗?)。因此,选择 close x的数字。在大多数应用程序中,这是“足够接近”。但出于同样的原因:永远不要相信float,即永远不要问“是x = 5?”。