使用以下代码:
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
为什么获得的值无法预测或存在模式?
这属于每个程序员都应该了解的关于浮点的内容。浮点的工作方式意味着某些数字不能完全用浮点表示。解释这一点的最简单方法是要求您将值 1/3 写为十进制数。一开始你很开心,但最终你的纸用完了。原因是在以十为基数的符号中,数字 1/3 是无限长的,因此在使用以十为基数的符号来存储数字的合理编码系统中,它的长度是有限制的。
浮点做同样的事情,但使用底数 2。这意味着对我们来说似乎很简单的数字,例如 1/10 或 0.1,变得无限递归。当您打印数字时,这会导致舍入错误,仅仅是因为您存储的数字不是您提供给编译器的数字,因为无法存储该数字。
这方面的规范论文是http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html,读起来很费劲,但解释了所有这些以及更多内容。
这是因为C 使用IEEE 754 32 位浮点格式来存储浮点数。float
您拥有的尾数被转换为二进制并存储在变量所需的 4 字节空间的低 23 位中。有时它可以完全转换为精确的二进制,有时它可能无法完全转换,因此存储了数字的截断形式,当从内存中读取时,它的计算结果略有不同。
此行为类似于在数学中使用1/3
0.33 或 0.333 的值,具体取决于您对精度的要求。
尝试使用:
f = 0.25;
或,
f = -15.625;
或,任何可精确转换为二进制的十进制值,您将得到正确的结果。
With float
or double
you have a certain amount of bits to represent your number x
in the computer. For float
it's usually 32 bits and double
has 64 bits.
The result of that? You can only store 2^32 different numbers in a float
and 2^64 in a double
. Since there is an infinite amount of "other" numbers, it means that these cannot be represented. But people still want to use these numbers (a compiler error about the unuseability of a number would be odd, wouldn't it?). Therefore, a number close to x
is chosen. In most applications, this is a "close enough". But for the same reason: Never trust a float
, i.e. never try to ask "is x = 5?".