9

我有这个简单的代码行:

float val = 123456.123456;

当我打印此 val 或查看范围时,它存储值 123456.13

好的,没关系,它不能将点后的所有数字都存储在 4 个字节中,但为什么它会在点后变成 13?不应该是12吗?

(在win32上使用vc++ 2010 express)

4

5 回答 5

10

在二进制中,123456.123456 是 11110001001000000.000111111001...(无限)。它四舍五入为 11110001001000000.001 或 123456.125。打印时四舍五入为 123456.13

于 2012-02-17T13:24:40.000 回答
8

存储的值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'”

于 2012-02-17T13:22:30.617 回答
7

当表示为浮点数时,您的数字的指数为 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 计算器

于 2012-02-17T13:26:44.960 回答
2

尝试打印 的值std::numeric_limits<float>::digits10。这大致是浮点数以 10 为底的精度。你试图超过它,所以你会遇到精度损失(这意味着超出有效数字的数字没有真正意义)。

参见例如numeric_limits<double>::digits10 的含义是什么

于 2012-02-17T13:15:43.330 回答
2

它完全依赖于编译器。在 GCC 中检查它。应该是 xxx.12

于 2012-02-17T13:17:04.267 回答