一、表示方法
在计算机中,浮点数一般由三部分组成:符号位+阶码+尾数。
这种浮点数是用科学记数法来表示的,即:浮点数=符号位.尾数×2^阶码。
根据IEEE 754国际标准,常用的浮点数有三种格式:
(1) 单精度浮点数(32位),阶码8位,尾数24位(内含1位符号位)。
(2) 双精度浮点数(64位),阶码11位,尾数53位(内含1位符号位)。
(3) 临时浮点数(80位),阶码15位,尾数65位(内含1位符号位)。
根据IEEE 754标准,符号位也是“0”代表正数;“1”代表负数。
尾数规格化形式,格式如下:1.XXX…X,由于最高位总是1,因此省略,称隐藏位(临时实数则不隐藏)。
阶码部分,即[E]移=2^(n-1)+E=127+E
这样,尾数与通常意义的尾数的含义不一致,为了区别,754 中的尾数称为有效数。
二、对上溢和下溢的处理
当运算结果小于规格化浮点数所能表示的最小值时,以前硬件处理策略,或者结果置0或者产生一个下溢陷阱,这两种方案均不能令人满意。
IEEE754处理方法是使用非规格化数。这时阶码为0(即移码-127),尾数没有隐含位,最高位是0。
这样的结果是降低精度,扩大表示范围。如原来规格化单精度最小值是1.0x2^-126,而非规格化单精度最小值是2^-23 x2^-126=2^-149(只有1位有效位) 。
对上溢用无穷大表示,同时规定:
无穷大+任何数=无穷大
任何有限数÷0=无穷大
任何有限数÷无穷大=0
无穷大÷无穷大=NaN (Not A Number)
三、十进制数转换成浮点数的步骤
1、将十进制数转换成二进制数:
整数部分用2来除,小数部分用2来乘;
2、规格化二进制数:
改变阶码,使小数点前面仅有第一位有效数字;
3、计算阶码:
短型浮点数的阶码加上偏移量7FH
长型浮点数的阶码加上偏移量3FFH
扩展型浮点数的阶码加上偏移量3FFFH
长型浮点数的阶码加上偏移量3FFH
扩展型浮点数的阶码加上偏移量3FFFH
4、以浮点数据格式存储。
把数值的符号位、阶码和尾数合在一起就得到了该数的浮点存储形式。例1 把十进制数100.25转换成协处理器中的浮点数
解:(1)进制转换:
(100.25)10=(1100100.01)2
(2)规格化:
(1100100.01)2=1.10010001×2^6 =1.10010001×2^110
(3)计算阶码:
110+01111111=10000101
(4)数值的符号位为:0
阶码为:10000101
尾数为:
1001 0001 0000 0000 0000 000
综合上述可得:
(100.25)10的浮点形式为:
010000101 10010001000000000000000
(100.25)10的浮点形式为:
010000101 10010001000000000000000
几个特殊数据的存储规则:
正0:所有的数据位都是0;
负0:最高位为1,其它的数据位是0;
正/负无穷:符号位为0/1,阶码位全为1,有效数字全为0;
NAN:非法的浮点数,阶码位全为1,有效数字不全为0;
正0:所有的数据位都是0;
负0:最高位为1,其它的数据位是0;
正/负无穷:符号位为0/1,阶码位全为1,有效数字全为0;
NAN:非法的浮点数,阶码位全为1,有效数字不全为0;
四、浮点数转换成十进制数的步骤
该步骤与前面“十进制数转换成浮点数”的步骤是互逆的,其具体步骤如下:
1、分割数字的符号、阶码和有效数字;
1、分割数字的符号、阶码和有效数字;
2、将偏移阶码减去偏移,得到真正的阶码;
3、把数字写成规格化的二进制数形式;
4、把规格化的二进制数改变成非规格化的二进制数;
5、把非规格化的二进制数转换成十进制数。
例2 把浮点数1100000111001001000000000000转换成十进制数。
解:
(1) 把浮点数 1100000111001001000000000000分割成三部分,可得:
符号位是1,
阶码 是10000011
尾数 是1001001000000000000
解:
(1) 把浮点数 1100000111001001000000000000分割成三部分,可得:
符号位是1,
阶码 是10000011
尾数 是1001001000000000000
(2) 还原阶码:
10000011 – 01111111=100
(3) 该浮点数的规格化形式:
1.1001001×24
(其中前面的“1.”从隐含位而来)
(4) 该浮点数的非规格化形式:
11001.001
(5) 该浮点数的十进制数为-25.125 (因为符号位为1,所以,该数是负数)
10000011 – 01111111=100
(3) 该浮点数的规格化形式:
1.1001001×24
(其中前面的“1.”从隐含位而来)
(4) 该浮点数的非规格化形式:
11001.001
(5) 该浮点数的十进制数为-25.125 (因为符号位为1,所以,该数是负数)
五、误差举例
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { float p = 5.1f; int f = (int)(p*100); printf("%d\n", f); system("pause"); return 0; }
原因分析:
5.1的浮点数表示:
5 = (101)2
0.1 = 0.0 0011 0011 0011 0011 0011 0011 .....(无限循环)
5 = (101)2
0.1 = 0.0 0011 0011 0011 0011 0011 0011 .....(无限循环)
所以 5.1 = 101.0 0011 0011 0011 0011 0011 0011 0011 0011...
5.1 = 1.010 0011 0011 0011 0011 0011 0011 0011 0011 0011... * 2^2
故
符号位(1位):0
阶码(8位):2+127=(1000 0001)2
尾数(23位):0100
0110 0110 0110 0110 011
综上5.1的浮点数表示是:
0100 0000 1010 0011 0011 0011 0011 0011
0100 0000 1010 0011 0011 0011 0011 0011
这个数化为10进制整数的时候,由于不可能达到5.1(5.099..),乘以100后被截断为509
六、表示范围、有效数字与截断误差
1、浮点数取值范围:
负数取值范围为 -3.4028235E+38 到 -1.401298E-45,正数取值范围为 1.401298E-45 到 3.4028235E+38。2、双精度数取值范围:
负值取值范围-1.79769313486231570E+308 到 -4.94065645841246544E-324,正值取值范围为 4.94065645841246544E-324 到 1.79769313486231570E+308。3、有效数字
单精度数的尾数用23位存储,加上默认的小数点前的1位1,2^(23+1) = 16777216。因为 10^7 < 16777216 < 10^8,所以说单精度浮点数的有效位数是7位。
双精度的尾数用52位存储,2^(52+1) = 9007199254740992,10^16 < 9007199254740992 < 10^17,所以双精度的有效位数是16位。
双精度的尾数用52位存储,2^(52+1) = 9007199254740992,10^16 < 9007199254740992 < 10^17,所以双精度的有效位数是16位。
4、截断误差
发生截断误差的情况
(1)数据越界
表示的数据大于能够表示的最大数,或小于最小数
(2)无限循环
0.1(二进制表示时无限循环)
(3)有效数字位数大于最大有效位数
3.123456789