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

Kos*_*mos 9 c++ floating-point digits ieee-754 floating-point-precision

我有这个简单的代码行:

float val = 123456.123456;
Run Code Online (Sandbox Code Playgroud)

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

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

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

Ric*_*gan 10

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


Lih*_*ihO 8

存储的值val等于123456.125.你得到了,.13因为你正在四舍五入:

float val = 123456.123456;
printf("%.4f %.2f\n", val, val);
Run Code Online (Sandbox Code Playgroud)

输出: 123456.1250 123456.13

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


das*_*ght 7

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

123456.123456 / 65536 = 1.8837909462890625
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

如果你想玩其他数字和浮动表示,这是一个非常有用的IEEE-754计算器.

  • @dasblinkenlight充其量这个描述是误导性的.舍入首先以二进制(到24位),十进制到二进制转换,然后到printf中的十进制.储存值为1.1110001001000000001 x 2 ^ 16 = 1.8837909698486328125 x 2 ^ 16 = 123456.125.它打印为123456.13,但只是因为Visual C++使用"从零开始的一半"舍入(参见我的文章http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/.) (3认同)