为什么float变量通过以一种奇怪的方式在点后切割数字来保存值
Why float variable saves value by cutting digits after point in a weird way?
我有一个简单的代码行:
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
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 如何在c++中为模板函数实例创建快捷方式
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 在c代码之间共享数据的最佳方式
- 在C++中将函数压缩为两种方式
- 以螺旋方式打印矩阵的程序.(工作不好)
- 文件追加的方式是,它在每次保存C++后结束行
- 如何求解方程并以正确的方式保存
- 保存代码版本 (Xcode) 的优雅方式
- IPersistFile::Save方法始终无法保存快捷方式
- C++在成员变量中保存不同类型数据的优雅方式
- 为什么float变量通过以一种奇怪的方式在点后切割数字来保存值
- 保存数据以便在体素编辑器中重复使用的最佳方式
- 保存图节点的最佳方式
- 保存源函数的最佳方式
- 在Emacs中保存-编译-执行c++程序的快捷方式
- 用unicode文件名保存文件的问题-如何以跨平台的方式正确保存UTF-8文件名
- 保存应用程序设置 MFC CArchive 方式
- VB和C++ActiveX控件以不同的方式保存其信息,如何实现C++ActiveX控件来代替VB ActiveX