为什么float变量通过以一种奇怪的方式在点后切割数字来保存值

Why float variable saves value by cutting digits after point in a weird way?

本文关键字:方式 保存 数字 变量 float 一种 为什么      更新时间:2023-10-16

我有一个简单的代码行:

float val = 123456.123456;

当我打印这个val或在范围内查找时,它存储值123456.13

好吧,这很好,它不能只在4个字节中存储点后的所有数字,但为什么它在点后变成13呢?不是应该是12点吗?

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

在二进制中,123456.123456是11110001001000000.0001111111001…(无穷大)。四舍五入为11110001001000000.001或123456.125打印时,四舍五入为123456.13。

存储在val中的值等于123456.125。你得到.13是因为你四舍五入:

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

输出:123456.1250 123456.13

在这种情况下,您应该使用double来避免截断。编译器还应警告您:"警告C4305:"initializing":从"double"截断为"float"

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

123456.123456 / 65536 = 1.8837909462890625

为了适应32位浮点,尾数被截断为23位,所以现在它变成了1.883791。当乘以65536时,它变为123456.125

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

EDIT四舍五入解释:(Rick Regan评论)

舍入首先发生在二进制(到24位)中,在十进制到二进制的转换中,然后发生在printf中的十进制。存储的值为1.1111000001000000001 x 2^16=1.8837909698486328125 x 2^16=12346.125。它打印为123456.13,但这只是因为Visual C++使用了"离零取整一半"取整。

里克也有一篇关于这个主题的优秀文章。

如果你想玩其他数字及其浮点表示,这里有一个非常有用的IEEE-754计算器。

尝试打印std::numeric_limits<float>::digits10的值。这大致是说一个浮子在底座10中有多精确。你试图超过它,所以你正在经历精度的损失(这意味着超过有效数字的数字实际上没有意义)。

参见例如numeric_limits<double>:数字10

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