为什么浮动变量通过以奇怪的方式在点之后切割数字来节省值?

时间:2012-02-17 13:11:47

标签: c++ floating-point ieee-754 floating-point-precision digits

我有这个简单的代码行:

float val = 123456.123456;

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

好吧,没关系,它只能在4个字节之后存储所有那些数字,但为什么它在点之后会产生13?不应该是12?

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

5 个答案:

答案 0 :(得分:10)

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

答案 1 :(得分:8)

val中存储的值等于123456.125。你得到的是.13,因为你正在围绕它:

float val = 123456.123456;
printf("%.4f %.2f\n", val, val);

输出:123456.1250 123456.13

在这种情况下,您应该使用double来避免截断。编译器也应该警告你: “警告C4305:'初始化':从'double'截断到'float'”

答案 2 :(得分:7)

当表示为浮点数时,您的数字的指数为16(即该值是其尾数乘以2 ^ 16或65536)。然后mantisse变成

123456.123456 / 65536 = 1.8837909462890625

为了适应32位浮点数,mantisse被截断为23位,所以它现在变为1.883791。如果再乘以65536,则会变为123456.125

请注意小数点后第三个位置的5:您使用的C ++输出例程将其舍入,使您的最终数字看起来像123456.13

编辑四舍五入的解释:(瑞克里根的评论)

舍入首先以二进制(24位),十进制到二进制转换,然后到printf的十进制。储存值为1.1110001001000000001 x 2 ^ 16 = 1.8837909698486328125 x 2 ^ 16 = 123456.125。它打印为123456.13,但只是因为Visual C ++使用“从零开始的一半”舍入。

Rick也有outstanding article on the subject

如果您想使用其他数字及其浮动表示,则此处为very useful IEEE-754 calculator

答案 3 :(得分:2)

尝试打印std::numeric_limits<float>::digits10的值。这粗略地说明浮子10具有多少精度。你试图超越它,所以你正在经历精度的损失(意味着超出重要数字的数字并没有真正意义)。

参见例如What is the meaning of numeric_limits<double>::digits10

答案 4 :(得分:2)

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