IEEE浮点表示(IEEE 754)
¶简介
浮点数是我们在程序里常用的数据类型,它在内存中到底是怎么样的形式存在的呢?
现代计算机中,一般都以IEEE 754标准存储浮点数,IEEE标准用: V=(-1)^s x M x 2^E 来表示一个浮点数
- 符号: s决定这个数是正数还是负数
- 尾数: M是一个二进制小数
- 阶码: E是对浮点数进行加权,权重是2的E次幂
符号 | 阶码 | 尾数 |
---|---|---|
sign | exponent | fraction |
对于不同长度的浮点数,阶码与小数位分配的数量不一样,如下:
精度 | 数符 | 阶码 | 尾数 | 总位数 | 偏移值 |
---|---|---|---|---|---|
单精度(C中的float) | 1 | 8 | 23 | 32 | 127 |
双精度(C中的double) | 1 | 11 | 52 | 64 | 1023 |
对于32位的单精度浮点数,数符分配是1位,阶码分配了8位,尾数分配了是23位。
根据这个标准,我们来尝试把一个十进制的浮点数转换为IEEE 754标准表示。
¶规格化的值
最普遍的情况,当exp的位模式不全为0(数值0),也不全为1(单精度255,双精度2047)
例如:178.125
-
先把浮点数分别把整数部分和小数部分转换成2进制
-
整数部分用除2取余的方法,求得:10110010
-
小数部分用乘2取整的方法,求得:001
-
合起来即是:10110010.001
-
转换成二进制的浮点数,即把小数点移动到整数位只有1,即为:1.0110010001 * 2^111,111是二进制,由于左移了7位,所以是111
-
-
把浮点数转换二进制后,这里基本已经可以得出对应3部分的值了
-
数符:由于浮点数是正数,故为0.(负数为1)
-
阶码 : 阶码的计算公式:阶数 + 偏移量, 阶码是需要作移码运算,在转换出来的二进制数里,阶数是111(十进制为7),对于单精度的浮点数,偏移值为01111111(127)[偏移量的计算是:2^(e-1)-1, e为阶码的位数,即为8,因此偏移值是127],即:111+01111111 = 10000110
-
尾数:小数点后面的数,即0110010001
-
最终根据位置填到对位的位置上:
数符 阶码 尾数 0 1 0 0 0 0 1 1 0 0 1 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 阶码与尾数之间隐含小数点
-
可能有个疑问:小数点前面的1去哪里了?由于尾数部分是规格化表示的,最高位总是“1”
我们将尾数定义为M=1+f,小数字段被描述为小数值f,其中0<=f<1,其二进制表示为:
也就是二进制小数点在最高有效位的左边。
我们也可以把M看成一个二进制表达式为下图的数字,也总能调整阶码使得尾数M的范围在1到2之间。
既然第一位总是1,那就可以直接隐藏不需要显示出来,同时也能够获得一个额外的精度位。
¶非规格化的值
当阶码全为0时,所表示的数非规格化的形式。这种情况下,阶码的值是1-Bias,尾数M=f,也就是小数字段的值,不包含隐含开头的1。
非规格化有两个用途:
- 一是提供一种表示数值0的方法,因为使用规格化的数我们必须使M>=1,无法表示0。
- 二是表示那些非常接近0的数。
¶拓展
¶乘2取整法
考虑一个十进制小数0.123,我们可以用“乘10取整”法得到它的每一位小数:第一位小数是0.123 *10=1.23,取整数1;第二位小数:0.23 *10=2.3,取整数2
上面的方法供你直观理解,下面我们从数学的角度分析其中的原理。
现在有一个十进制小数为0.625,要把它转换为二进制小数,我们需要找到它的每一位。记这个二进制小数点后第1位是$a_1$,第二位是$a_2$,……,那么这个小数的值就是$ a_1 \ast {\frac{1}{2}}^{-1}+a_2 \ast {\frac{1}{2}}^{-2}+a_3 \ast {\frac{1}{2}}^{-3}+… $ 。现在我们的目标是根据0.625找到对应的$ a_1,a_2,a_3$ ,…使得$ 0.625=a_1 \ast {\frac{1}{2}}^{-1}+a_2 \ast {\frac{1}{2}}^{-2}+a_3 \ast {\frac{1}{2}}^{-3}+… $
在等式两边同时乘以2,得到$1.25=a_1 \ast {\frac{1}{2}}^{0}+a_2 \ast {\frac{1}{2}}^{-1}+a_3 \ast {\frac{1}{2}}^{-2}+…$
我们发现,左边的整数部分1对应右边的$a_1$,也就是二进制小数的第一位,于是$a_1=1$,对于剩下的部分:
$0.25=a_2 \ast {\frac{1}{2}}^{-1}+a_3 \ast {\frac{1}{2}}^{-2}+…$
我们再次乘以2,得到$0.5=a_2 \ast {\frac{1}{2}}^{0}+a_3 \ast {\frac{1}{2}}^{-1}+… $于是$a_2=0$
再乘以2,得到$1=a_3 \ast {\frac{1}{2}}^{0}+…$, 于是$a_3=1$,到这里,所有的数都消耗完了,我们找到了0.625对应的二进制小数:0.101