我有这个简单的代码行:
float val = 123456.123456;
当我打印此 val 或查看范围时,它存储值 123456.13
好的,没关系,它不能将点后的所有数字都存储在 4 个字节中,但为什么它会在点后变成 13?不应该是12吗?
(在win32上使用vc++ 2010 express)
我有这个简单的代码行:
float val = 123456.123456;
当我打印此 val 或查看范围时,它存储值 123456.13
好的,没关系,它不能将点后的所有数字都存储在 4 个字节中,但为什么它会在点后变成 13?不应该是12吗?
(在win32上使用vc++ 2010 express)
在二进制中,123456.123456 是 11110001001000000.000111111001...(无限)。它四舍五入为 11110001001000000.001 或 123456.125。打印时四舍五入为 123456.13 。
存储的值val
等于123456.125
。你得到.13
是因为你正在四舍五入:
float val = 123456.123456;
printf("%.4f %.2f\n", val, val);
输出:123456.1250 123456.13
在这种情况下,您应该使用 double 以避免截断。编译器还应该警告您:“警告 C4305: 'initializing' : truncation from 'double' to 'float'”。
当表示为浮点数时,您的数字的指数为 16(即该值是其尾数乘以 2^16 或 65536)。螳螂然后变成
123456.123456 / 65536 = 1.8837909462890625
为了适应 32 位浮点数,尾数被截断为 23 位,所以现在变成1.883791
. 再乘以65536
,就变成了123456.125
。
请注意5
小数点后第三位的 :您使用的 C++ 输出例程将其四舍五入,使您的最终数字看起来像123456.13
.
编辑四舍五入的解释:(Rick Regan 的评论)
舍入首先以二进制(到 24 位),十进制到二进制转换,然后到十进制,在printf
. 存储的值为 1.1110001001000000001 x 2^16 = 1.8837909698486328125 x 2^16 = 123456.125。它打印为 123456.13,但这只是因为 Visual C++ 使用“距零的一半”舍入。
Rick 也有一篇关于这个主题的优秀文章。
如果您想使用其他数字及其浮点表示,这里有一个非常有用的 IEEE-754 计算器。
尝试打印 的值std::numeric_limits<float>::digits10
。这大致是浮点数以 10 为底的精度。你试图超过它,所以你会遇到精度损失(这意味着超出有效数字的数字没有真正意义)。
它完全依赖于编译器。在 GCC 中检查它。应该是 xxx.12