该文主要介绍一个浮点数在计算机中的表示,属于很底层的知识点
介绍计算机如何表示浮点数之前,先了解一下日常生活中,我们人类如何使用十进制表示一个很大的数(假设这个要表示的数是二百万,200 0000)。假如是一个更大的数,表示起来将更加不方便,因此,我们可以使用科学计数法表示为2*10^6 ;0.000002则常常表示为2*10^-6。
计算机表示二进制浮点数采用了类似的表示方法。假入有一个数,1101 0000。先不管这个数对应的十进制值是多少,考虑一下如何在计算机中存储。像unsigned int 那样直接将对应的位存储在相应的空间完全没有问题,但是如果这个数后面还有很多个0呢,因此,我们这里将这个数看作1.101*2^7(本文不对该表示法原理多做介绍),然后将1.101和7分别存储在相应空间的两个部分,就像我们把东西分门别类放在收纳袋里一样。
以上只是一个粗浅的策略,仅限于我和看了我这个策略的人能够共同遵守,我们这样把一个数放在收纳袋中拿给别人,别人并不能立即把收纳袋中的数复原。因此IEEE设计了一个更加巧妙并有前瞻性的收纳袋,想要存储数的人把数的各部分按照规则放好,想要读取这个数的人按照规则将各部分取出拼凑即可获得该数。(这让我感到沟通即妥协)
1. IEEE浮点标准
V=(-1)^s * M * 2^E
- 符号(sign):s决定该数的正负
- 尾数(significand):M是一个二进制小数
- 阶码(exponent):E对浮点数加权(也许有人对这个理解的不够,我这里暂时无法对此详细解释)
有些概念不好理解,或者表示不清晰。我们用一个数来协助理解——1101 0000 0000 0000 0000。该数用浮点标准表示为(-1)^0 * 1.101 * 2^15,在这个例子中,s=-1,M=1.101,E=15所以我们最终存储的就是这三个参数。
浮点数表示有两种,float和double,区别在于M和E的取值范围。
根据E的取值,被编码的值分成三种情况。E是浮点数的权值,通俗说就是后面究竟有多少个值。怎么理解权值这个概念呢?我们都是1.101,但是我后面有15个0,你后面只有1个0,那我权重15就可以秒杀你的权重1,这就是权的绝对力量。我们不一样!
当E上每一位都为0的时候,为非规格化的值;当E上每一位都为1的时候,为特殊值;剩余的情况即为规格化的值。
1.1 规格化的值
1.1.1 exp字段
考虑科学计数法表示整数的时候,E取值为正数或0;表示小数的时候,E取值为负数,因此E应为一个有符号整数。这里没有采取再设置一个E的符号位的方式,而是采用偏置形式来表示有符号整数。
简单说来就是设定一个数,我们称之Bias。若E的原始值大于Bias(在Bias的右边),则阶码的值为正数;若E的原始值小于Bias(在Bias的左边),则阶码的值为负数。很明显这里将exp字段设计的更加复杂也是为了妥协,至于为什么这里采用偏执而不是设置符号位的方式,我不清楚。
E=e-Bias
e是无符号数
Bias=2^(k-1)-1
以exp字段为1001 0011为例,Bias为0111 1111=127
E=1001 0011 - 0111 1111=0001 0011=19
1.1.2 frac字段
frac字段为小数字段,鉴于一个二进制小数可以化为1.x*2^E的形式,可以将1.x中的1省略不表示,反正每一个数最终都包含1,这就叫做共识。因为省略了1,因此在最终计算结果的时候需要加1,尾数定义为M=1+f,f的二进制表示为0.fn-1 ... f1 f0
1.2 非规格化的值
非规格化的值exp字段全为0,阶码值E=1-Bias,尾数M=f。
非规格化数两个用途:
- 表示数值0
- 表示非常接近于0.0的数
在规格化值的规则设定中,我们默认M是一个范围为(1<=M<2)的数,这就导致我们可以表示0.00...01这个很接近0的小数,却没法用浮点数表示0。考虑到这点,我们规定当exp字段全为0的时候,阶码值E=1-Bias(127),而根据公式M*2^E可以看出,无论M在表示范围内取何值,都避免不了结果趋近于0.0的命运,此即权值对数的影响。相对于人而言,无论我们掌握了多少的技能,不会思考都将限制我们的人生,这就是为什么我现在的人生如此悲惨的根由吧。
回到主线,按照规格化的方式(M=1+f),虽然我们也最终可以无限接近于0.0,但是总有个1在那里,因此我们设定了非规格化的规则,M=f。这样一来,我们最终将的到0(M=0)。
需要注意的是,根据s字段的值,我们将会有+0.0(s=1)和-0.0(s=0)。这两个值在某些方面被认为是不同的,至少在存储中不同。
1.3 特殊值
exp字段全为1。
我们还是先分析权,E将会是一个很大的值,导致权很大,可以用来表示无穷。
若frac字段全为0,得到的值表示无穷,当s=0为+无穷,s=1表示-无穷。
若frac字段不全为0,结果值被称为NaN,即不是一个值(Not a Number),可以用来表示某些运算导致出现非实数的结果,例如对-1求平方根,或计算正无穷-正无穷。
2. 示例
假设一个基于IEEE浮点格式的5位浮点表示,1个符号位、2个阶码位(k=2)和2个小数位(n=2),列举这个5位浮点表示的全部非负取值范围。
位 | e | E | $2^E$ | f | M | $2^E*M$ | V | 十进制 |
---|---|---|---|---|---|---|---|---|
0 00 00 | 0 | -1 | $1\over2$ | $0\over4$ | $0\over4$ | $1\over2$ * $0\over4$ | $0\over8$ | +0.0 |
0 00 01 | 0 | -1 | $\frac{1}{2}$ | $1\over4$ | $1\over4$ | $1\over2$ * $1\over4$ | $1\over8$ | 0.125 |
0 00 10 | 0 | -1 | $1\over2$ | $2\over4$ | $2\over4$ | $1\over2$ * $2\over4$ | $2\over8$ | 0.25 |
0 00 11 | 0 | -1 | $1\over2$ | $3\over4$ | $3\over4$ | $1\over2$ * $3\over4$ | $3\over8$ | 0.375 |
0 01 00 | 1 | 0 | 1 | $0\over4$ | $4\over4$ | 1* $4\over4$ | $4\over4$ | 1 |
0 01 01 | 1 | 0 | 1 | $1\over4$ | $5\over4$ | 1* $5\over4$ | $5\over4$ | 1.25 |
0 01 10 | 1 | 0 | 1 | $2\over4$ | $6\over4$ | 1* $6\over4$ | $6\over4$ | 1.75 |
0 01 11 | 1 | 0 | 1 | $3\over4$ | $7\over4$ | 1* $7\over4$ | $7\over4$ | 1.75 |
0 10 00 | 2 | 1 | 2 | $0\over4$ | $4\over4$ | 2* $4\over4$ | $8\over4$ | 2 |
0 10 01 | 2 | 1 | 2 | $1\over4$ | $5\over4$ | 2* $5\over4$ | $10\over4$ | 2.5 |
0 10 10 | 2 | 1 | 2 | $2\over4$ | $6\over4$ | 2* $6\over4$ | $12\over4$ | 3 |
0 10 11 | 2 | 1 | 2 | $3\over4$ | $7\over4$ | 2* $7\over4$ | $14\over4$ | 3.5 |
0 11 00 | 3 | 2 | 4 | $0\over4$ | $4\over4$ | 4* $4\over4$ | $16\over4$ | 4 |
0 11 01 | 3 | 2 | 4 | $1\over4$ | $5\over4$ | 4* $5\over4$ | $20\over4$ | 5 |
0 11 10 | 3 | 2 | 4 | $2\over4$ | $6\over4$ | 4* $6\over4$ | $24\over4$ | 6 |
0 11 11 | 3 | 2 | 4 | $3\over4$ | $7\over4$ | 4* $7\over4$ | $28\over4$ | 7 |