内容:浮点表示、数值示例,程序示例
-
浮点表示
IEEE浮点标准用V=-1s * M * 2E的形式来表示一个数。
-
符号(sign): s决定数是负数(s=1)还是正数(s=0),而对于数值0的符号位解释作为特殊情况处理。
-
有效数(significand):M是一个二进制小数,它的范围在[1,2],或者[0,1)。(为什么是这两种范围,稍后解释)。
-
指数(exponent): E是2的幂(可能是负数),它的作用是对浮点数加权。
相对应的,浮点数的位表被划分成三个域,以编码这些值:
按高位到低位的顺序,
-
一个单独的符号位s直接编码符号s
-
k位的指数域exp=e k-1 … e 1 e 0编码指数E。
-
n位小数域frac=f n-1…f 1f 0编码有效数M,但是被编码的值也依赖于指数域的值是否等于零。
比如,float型,s,exp,frac分别为1位,k=8位和n=23位,产生一个32位的表示。
可以得到e的范围[0,255]。
double型,s,exp,frac分别为1位,k=11位和n=52位,产生一个64位的表示。
可以得到此时e的范围[0,2047]。
根据exp的值,被编码的值可以分为三种不同的情况:
-
规格化值(exp>0 && exp!=2k-1,即排除最大和最小的情况
exp此时解释为表示偏置(biased)形式的有符号整数,也就是说,指数的值实际为E=e-Bias,e即为exp的简写,位表示(ek-1 … e1 e0),而Bias是一个等于2k-1-1(单精度127,双精度1023)的偏置值。由此产生了指数的取值范围,单精度-126~+127,双精度-1022~+1023。
E对k位统一表示为(2-2k-1~2k-1-1)。
小数域frac解释为描述小数值f,其中0<=f<1,其二进制表示为0. fn-1…f1f0 ,也就是二进制小数点在最高有效位的左边。有效位定义为M=1+f。
f范围:0~1-2-n
-
非规格化值(exp==0),即exp所有位全为0。
此时指数值E=1-Bias。
而小数域M=f,也就是小数域的值,而不包含开头的1。
使指数值为1-Bias而不是0-Bias似乎很奇怪,稍后会看到,这提供了一种从非规格化值平滑转换到规格化值的方法。
在解释这个问题之前,先考虑下之前M=1+f而不是M=f是为什么?
如果我们希望表示的数值满足这样简单的规则:
随着E增大或者M增大时,相对应的浮点值都是增大的。
假设我们取M=1+f,而不是f。
以正数时为例,若M取f值而不是1+f时,则可以表示的范围是
min = 2E * 0 = 0;
max = 2E * (1-2-n);
很明显这样表示的数范围很奇怪,没有满足我们的规则。而且多个时候都是0的表示,有些混乱。
如果取M=1+f,
min = 2E *(1+0) = 2E;
max = 2E * (1+1-2-n) = 2E*(2-2-n);
则E增大时,比如Enew=E+1
此时min=2E+1 *(1+0)= 2E *2,正好大于之前的max,同时我们发现与之前的max差值为
2E*2n,也是指数域为E时,可表示的每个相邻数值的差值了。因此这样表示是非常平滑的。
不过问题是,此时我们无法表示0.0了。明显是由于我们令M=1+f而不是M=f引起的,于是我们在此时令M=f。不过这样又不平滑了,于是就有了E=1-Bias,而不是直觉的E=-Bias。
还有一个令人奇怪的问题就是,当符号位为1其他位全为0时,得到-0.0,IEEE在某些方面认为-0.0,+0.0是不同的,而其他方便是相同的……
-
特殊数值:
当指数域exp全为1时,我们用来表示正无穷或者负无穷。此时不考虑小数域的情况,事实上,我们认为小数域全为0即可,因为在计算机上定义一个数为正无穷没有意义。当指数域全为1时,只需要在看下符号位来确定+∞or-∞就好了。
-
数值示例
作为上面的进一步说明,举一个例子,假定浮点格式为8位,其中有k=4的指数位和n=3的小数位。偏置24-1-1=7。非规格划数的E=1-7=-6,得到2E=1/64。小数f的范围:
(0,1/8,…/7/8),从而得到非规格划数范围0~7/8*1/64=7/512。
8位浮点格式的非负值示例: word编辑的,表有些乱了。。。。
描述
位表示
e
E
f
M
V
0
最小的非规格划数
最小的非规格划数
0 0000 000
0 0000 001
0 0000 010
0 0000 011
…
0 0000 110
0 0000 111
0
0
0
0
0
0
0
-6
-6
-6
-6
-6
-6
-6
0
1/8
2/8
3/8
…
6/8
7/8
0
1/8
2/8
3/8
…
6/8
7/8
0
1/512
2/512
3/512
…
6/512
7/512
最大的规格划数
最大的规格划数
0 0001 000
0 0001 001
…
0 0110 110
0 0110 111
0 0111 000
0 0111 001
0 0111 010
…
0 1110 110
0 1110 111
1
1
…
6
6
7
7
7
…
14
14
-6
-6
…
-1
-1
0
0
0
…
7
7
0
1/8
…
6/8
7/8
0
1/8
2/8
…
6/8
7/8
8/8
9/8
…
14/8
15/8
8/8
9/8
10/8
…
14/8
15/8
8/512
9/512
…
14/16
15/16
1
9/8
10/8
…
224
240
无穷大
0 1111 000
------
-----
-----
------
-----
可以看到,如果将表的值的位表达式解释为无符号整数,它们就是按升序排列的,就像它们表示的浮点数一样。这不是偶然的,IEEE格式如此设计就是为了浮点数能够使用整数排序函数来进行排序。
有几个固有的属性:
-
值+0.0总有一个全为0的位表示
-
最小的正非规划值有一个位表示,是由最低有效位为1而其他所有位为0构成的。它具有小数(和有效数)值M=f=2 -n和一个指数值E=-2 k-1+2。
-
最大的非规格化值位模式有全为0的指数域和全为1的小数域组成。仅比最小的正规格化值小一点。
-
最小的正规格化值位模式的指数域的最低有效位为1,其余全为0.有效值M=1.
-
最大的规格化值的位表示的符号位为0,指数的最低有效位位0,其他全为1.它的小数值f=1-2 -n,有效值M=2-2 -n,指数值E=2 k-1-1。
-
-
程序示例
程序分别打印了12345以及12345.0的位表示。
打印了两者位相同的最长部分,以及几个比较大的浮点数。
程序本身不重要,直接看下结果:
zhy@desktop:~/doublemint/factory$ ./a.out
0 0000 0000 0000 0000 0110 0000 0111 001
0 1000 1100 1000 0001 1100 1000 0000 000
1001 1100 0000 1
16777216.000000
16777216.000000
33554432.000000
12345,12345.0重复的部分从第10位开始,恰好是12345除去最高位1后的部分。
12345具有二进制表示[11000000111001]。通过向二进制小数点右边移动13位,我们创建这个数的一个规格化表示,得到12345 = 1.10000001110012x213。为了用IEEE单精度形式来编码,我们丢弃开头的1,并且在末尾增加10个0,来构造小数域,得到二进制表示[1000001110010000000000].为了构造指数域,我们增加偏置量127到13,得到140,其二进制表示位[10001100]。加上符号位0,就得到二进制的浮点表示:
0 1000 1100 1000 0001 1100 1000 0000 000
-
现在我们可以看到,相关的区域对应整数的低位,刚好在最高的等于1的位之前停止(这个位就是隐含的开头的位1),和浮点表示的小数部分的高位是相匹配的。
再举个例子,0.5浮点位怎么表示的?
符号位为0
0.5=1*2-1*(1+0),对应与E=-1的情况,再加上Bias,[01111110]
小数位为[0000…000]
因此0 0111 1110 0000 0000 0000 0000 0000 000
1.5 = 1* 1 * (1 + 2-1),E=0,即[01111111]。
小数位为[1000…0000]
因此0 0111 1111 1000 0000 0000 0000 0000 000。
12345 = 1.10000001110012x213
可以得到12345.5 = 1.100000011100112x213
因此12345.5的浮点数表示为: 0 1000 1100 1000 0001 1100 1100 0000 000
最后打印的浮点数跟下题有关:
假定一个k位指数和n位小数的浮点格式,给出不能准确描述的最小正整数的公式(因为要想正确表示它需要n+1位小数),对于单精度格式这个整数是多少?
这个数字的二进制表示为:1后面跟着n个0,其后再跟1,得到值是2n+1+1。
当n=23时,值为224+1。













