IEEE 浮点数编码
date
Oct 6, 2022
slug
IEEE
status
Published
tags
CSAPP
type
Post
summary
IEEE浮点数编码
IEEE 浮点数编码
二进制小数
首先看一下定点数表示法。形如$d_md_{m-1}...b_1b_0.b_{-1}b{-2}...b_{-m-1}b_{-m}$的表示,其中b的取值为0或者1,小数点左边的位的权是2的正幂,小数点右边的位的权是2的负幂。
小数点二进制表示法不能表示$x\times2^y$这样的数字,比如$\frac{1}{5}$是0.2,二进制中我们只能近似的表示。并且位数越大,精度越高。
如果用已有的二进制编码知识来表示数值159 / 16,那么只需要分配一段内存区域来存储159的二进制串10011111,然后再利用另一段区域来存储小数点相关的偏移量00000100即可。不过这种方式灵活性比较低,所能够表示的数值范围也十分有限。那么接下来看看现代机器中浮点数是如何表示的。
IEEE浮点表示
基本原理
IEEE浮点数表示法说白了就是科学计数法,十进制中,表示0.0011 那么这个数可以表示为$11\times10^{-4}$。可以简洁的概括为$n\times10^k$。同理,在二进制中就是$M\times2^E$。M是尾数,影响浮点数的精度,E是阶码,影响浮点数的大小。
IEEE浮点表示会把一个二进制串分成3部分,分别用来存储浮点数的尾数,阶码以及代表浮点数正负的符号位。不过在IEEE浮点数中尾数以及阶码并不是直接存储的,而是需要特殊的编码方式。
IEEE的浮点标准用$V=(-1)^s \times M \times 2^E$来表示一个数
- S:符号位,为1的时候是负数,为0的时候是正数
- M: 尾数:本质上是一个无符号数,范围是
[1,2)
或者[0,1)
- E: 阶码:作用是对浮点数进行加权,权重是2的E次幂。
不同精度浮点数中三个字段所占字节
规格化和非规格化的值
以32位浮点数为例,规格化和非规格化的值
规格化的值
阶码
在这种情况,阶码不完全为0,也不完全为1,本来表示的范围是[1-255]
二进制 | 表示的值 |
0000 0001 | 1 |
... | ... |
1111 1110 | 255 |
但是阶码字段被解释为以偏置值形式表示的有符号正数,说人话就是要加上偏置值:$E = e - Bias$
TODO: 为什么要偏置
$$
Bias = 2^{k - 1} - 1 (k为阶码的位数)
$$
实际表示的范围:
二进制 | 表示的值 |
… | … |
1111 1110 | 255 |
尾数
小数字段frac被解释为小数值f,其中f的范围是
[0,1)
,二进制表示为$0.f_{n-1}....f_1f_0$。二进制小数点在最高位的左边。尾数定义为:
$$
M = 1 + f
$$
为什么需要加1呢?
分析一下
有效位数是被限制的,前导0会占用很大空间,得出结论,前导0越多,有效数字越少,去除前导0才能使得有效数字最大化。这就是用IEEE浮点数编码的原因,本质上是科学计数法。比如3/4是0.11,有效数字是11,但是0.11确用了三位,3/16是0.0011,有效数字仍然有两位,于是写成$1.12^{-1}$和$1.12^{-3}$消除了前导0。
我们也发现除了0以外,有效数字的首位一定是1,于是这个1就被省略了,这种表示法讲所需要的有效数字位数减少了一位。
非规格化的值
阶码
阶码域全0.阶码值是
$$
E = 1 - bias
$$
对于32位来说,是1-127=-126
为什么不是
0-bias
呢?
因为平滑过渡的需要,假设8位浮点格式,k=4的阶码位和n=3的小数位,偏置是7
最大的规格化数:位表示 | E | $2^E$ | M | V |
0 0000 111 | -6 | 1/64 | 7/8 | 7/512 |
最小非规格化数:
位表示 | E | $2^E$ | M | V | 效果 |
0 0001 000 | -6 | 1/64 | 8/8 | 8/512 | ok |
0 0001 000 | -7(0-bias) | 1/128 | 8/8 | 8/1024 | no |
可以观察到最大非规格化数和最小规格化数的转变,1-bias而不是-bias补偿了非规格化数的尾数没有隐含开头的1.
尾数
尾数是$M=f$,不加隐含的1了,这是规定
非规格化的值作用
- 表示数值0,因为规格化的值,M总是大于等于1,表示不了0
- +0 符号位为1,阶码小数位为0
- 0 符号位为0,阶码小数位为0
- 表示距离0近的数(非规格化的值越靠近原点越稠密)
特殊值
网上很多,不再赘述了
数字示例
推荐工具:
单精度浮点数内存中编码双精度浮点数内存中编码