IEEE 754浮点数转换
Riguz Lee · 2019-06-27 · 刨根问底, 协议
一个小数的二进制是怎么样的呢?我们先看看一个二进制的小数怎么转换成十进制:
(1)
IEEE 754
IEEE 754 标准中规定了浮点数在计算机中的表示方法,主要就是单精度(float)和双精度(double):
S Exp Fraction
Single(32bit) ▯▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯
Double(64bit) ▯▮▮▮▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯其计算公式为:
(2)
其中,Bias为指数偏移值,是一个固定值,即 其中e为指数部分的比特长度。
- 单精度
- 双精度
举个例子,刚才我们算出来的小数可以这样表示:
(3)
因此在计算机中,表示为:
Float:
▯▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯
010000011110101011..............
Double:
▯▮▮▮▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯
010000000011110101011...........................................不足的部分补上0,即:
除了正常的浮点数外,还有几个比较特殊的:
十进制与二进制转换
计算方式为,将小数的整数部分与2取余倒序排列;将小数部分与2取整正序排列。例如,将3.14转换为float:
首先将整数部分直接转换为二进制
- $3\mod2 = \fbox{1}$
- $1\mod2 = \fbox{1}$
小数部分为0.14,不断乘以2后取整数部分,然后用小数继续乘以2直到值为1
- $0.14 \times 2 = \fbox{0}.28$
- $0.28 \times 2 = \fbox{0}.56$
- $0.56 \times 2 = \fbox{1}.12$
- $0.12 \times 2 = \fbox{0}.24$
- $0.24 \times 2 = \fbox{0}.48$
- $0.48 \times 2 = \fbox{0}.96$
- $0.96 \times 2 = \fbox{1}.92$
- $0.92 \times 2 = \fbox{1}.84$
- …..
- 重复以上步骤,得到
舍入操作
对于尾数多余精度的情况,需要舍去多余的部分,但不是按照四舍五入的方式,而是按照“向偶舍入”的方式,意思就是,如果多余的部分大于0.5(则最低位进1;如果小于0.5则舍去;如果正好是等于0.5则根据最低位判断,如果最低位是1则进位,否则舍去。这样按照统计学来看,对于一个小数有相同的机会进位或者被舍去。
例如对于上例中的3.14,我们可以得到:
(4)
因此3.14的float表示为:
▯▮▮▮▮▮▮▮▮▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯▯
01000000010010001111010111000011还原
那么,对于一个存储在磁盘上的浮点数,我们怎么将它加载到内存中来?对于C来说,实际也是采用的IEEE754标准(float, double),所以实际上浮点数在内存中的表示是一致的,直接转换即可:
struct ConstantFloat {
mutable u4 bytes;
float &getValue() const {
return *reinterpret_cast<float *>(&bytes);
}
};参考: