问题
- unsigned int a = 406682816;
- a = a+1.0f;
奇怪的就是: a 依然是 406682816, 并没有加一. 网上查了一些资料, 这里分享一下原因.
分析与验证
测试代码
- int a=406682816;
- int c=a+1.0f;
- int mask = 1;
- // 浮点类型的 a
- float fa = a;
- // 浮点类型的 a+1.0f
- float fc = a+1.0f;
- cout <<a << endl;
- cout << c << endl;
- cout << endl << "a bits" << endl;
- for (int i=31;i>=0;i-- )
- {
- cout <<((*((int*)&a))>>i & mask );
- }
- cout <<endl << "fa bits" << endl;
- for ( int i=31;i>=0;i-- )
- {
- cout <<((*((int*)&fa))>>i & mask );
- }
- cout <<endl << "fc bits" << endl;
- for ( int i=31;i>=0;i-- )
- {
- cout <<((*((int*)&fc))>>i & mask );
- }
- cout << endl;
输出
- 406682816
- 406682816
- a bits
- 00011000001111010111110011000000
- fa bits
- 01001101110000011110101111100110
- fc bits
- 01001101110000011110101111100110
- // fa 和 fc 的内存值完全一致
原因结论
float 类型的内存分布在 IEEE 754 标准里有规定: 对于大小为 32-bit 的浮点数 (32-bit 为单精度, 64-bit 浮点数为双精度, 80-bit 为扩展精度浮点数)
其第 31 bit 为符号位, 为 0 则表示正数, 反之为复数, 其读数值用 s 表示;
第 30~23 bit 为幂数, 其读数值用 e 表示;
第 22~0 bit 共 23 bit 作为系数, 视为二进制纯小数, 假定该小数的十进制值为 x;
float 类型的数值得出的公式计算示例如下 (截自网络):
20170215225457756.png
也即, float 类型可以用于数值计算的位数少于 int(只有 23 位), 通过符号位, 幂数以及系数位来做计算, 示例中做了 1.0f 的加法后, 并没有改变内存的布局, 所以值并未变化.
这里也从侧面提醒我们, 在做要求精度的计算时, 避免使用 float 类型是上佳之策, 否则, 即是我们明白 float 类型的计算原理依然会踩坑..
来源: https://www.qcloud.com/developer/article/1159379