27 Nov 2012

计算机中的浮点数表示方法

收藏到CSDN网摘

计算机中的浮点数,整数,负数表示方法,各种语言都会涉及这个问题,尤其是浮点数运算.


1. 原码,反码,补码

假设有一 int 类型的数,值为5,那么,我们知道它在计算机中表示为:
00000000 00000000 00000000 00000101
5转换成二制是101,不过int类型的数占用4字节(32位),所以前面填了一堆0。
现在想知道,-5在计算机中如何表示?

在计算机中,负数以其正值的补码形式表达(即:原码[正值]的反码+1)。
什么叫补码呢?这得从原码,反码说起。

1、原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。
比如 00000000 00000000 00000000 00000101 是 5的“原码”。

2、反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。
取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)
比如:将00000000 00000000 00000000 00000101每一位取反,
11111111 11111111 11111111 11111010
称:11111111 11111111 11111111 11111010 是 00000000 00000000 00000000 00000101 的反码。
反码是相互的,所以也可称:
11111111 11111111 11111111 11111010 和 00000000 00000000 00000000 00000101 互为反码。

3、补码:反码加1称为补码。
也就是说,要得到一个数的补码,先得到反码,然后将反码加上1,所得数称为补码。
比如:00000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。
那么,补码为:
11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011

所以,-5 在计算机中表达为:
11111111 11111111 11111111 11111011
转换为十六进制:0xFFFFFFFB。

再举一例,我们来看整数-1在计算机中如何表示。
假设这也是一个int类型,那么:
1、先取1的原码:00000000 00000000 00000000 00000001
2、得反码: 11111111 11111111 11111111 11111110
3、得补码: 11111111 11111111 11111111 11111111
十六进制表示: 0xFFFFFFFF

2. 十进制与二进制转化

计算机中的数字都使用二进制,而日常生活普遍使用十进制数.这就涉及到进制转换问题.具体来说,十进制整数与小树的转换方法不同.

1)十进制整数转二进制: 除2取余,逆序排列.具体做法是:用2去除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为0时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。例如:

254=(11111110)B
254/2=127=====余0   
127/2=63======余1   
63/2=31=======余1   
31/2=15=======余1   
15/2=7========余1   
7/2=3=========余1   
3/2=1=========余1   
1/2=0=========余1

 原理:假设一个十进制的数能够写成二进制的edcba形式那么这个十进制的数一定等于 a(2^0)+b(2^1)+c(2^2)+d(2^3)+e(2^4)将以上数列除以2,所得的余数是a,商是 b(2^0)+c(2^1)+d(2^2)+e(2^3)再除以二,余数为b。当这个数不能再被2除时,把所有的余数反过来写,就得到数列edcba。

2)十进制小数转二进制:乘2取整,顺序排列.具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,此时0或1为二进制的最后一位。或者达到所要求的精度为止。例如:

0.625=(0.101)B
0.625*2=1.25======取出整数部分1   
0.25*2=0.5========取出整数部分0   
0.5*2=1==========取出整数部分1   

再如:0.7=(0.1 0110 0110...)B   
0.7*2=1.4========取出整数部分1   
0.4*2=0.8========取出整数部分0   
0.8*2=1.6========取出整数部分1   
0.6*2=1.2========取出整数部分1   
0.2*2=0.4========取出整数部分0    
0.4*2=0.8========取出整数部分0   
0.8*2=1.6========取出整数部分1   
0.6*2=1.2========取出整数部分1   
0.2*2=0.4========取出整数部分0
...

原理:假设一个十进制数的小数部分能写成二进制数小数0.ab的形式,那么该二进制小数转化为十进制数就是a/2+b/4。这时将此十进制分数乘2,所得整数部分即为a。

3)二进制转十进制:从右到左用二进制的每个数去乘以2的相应次方(从0开始).或者叫加权求和.例如:
1101(2)=1*2^0+0*2^1+1*2^2+1*2^3=1+0+4+8=13.


3. 浮点数

 根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:
V = (-1)^S×M×2^E
在内存中表示为:
SEM
其中
(1)S表示符号位,当S=0,V为正数;当S=1,V为负数。
(2)M表示有效数字,大于等于1,小于2。
(3)E表示指数位。

例如:十进制的5.0,写成二进制是101.0,相当于1.01×2^2。那么,按照上面V的格式,可以得出s=0,M=1.01,E=2. 

M:
IEEE 754规定,对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。 对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。M可以写成1.xxxxxx的形式,其中xxxxxx表示小数部分。IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。

E:
E为一个无符号整数(unsigned int)。这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,E的真实值必须再减去一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。例如:2^4的E=4,保存时必须保存为4+127=131.

另外,E还有三种特殊情况:
(1) 当E全为0, M = 0时,表示0。
(2) 当E全为1, M = 0时,表示无穷大,用符号位来确定是正无穷大还是负无穷大。
(3) 当E全为1, M != 0时,表示NaN(Not a Number,不是一个数)。

例如:浮点数9.0,如何用二进制表示?
首先,浮点数9.0等于二进制的1001.0,即1.001×2^3。
那么,第一位的符号位S=0,有效数字M等于001后面再加20个0,凑满23位,指数E等于3+127=130,即10000010。
所以,写成二进制形式,应该是S+E+M,即0 10000010 001 0000 0000 0000 0000 0000。这个32位的二进制数,还原成十进制,正是1091567616。

浮点数加减法

设两个浮点数 X=Mx*2Ex ,Y=My*2Ey
实现X±Y要用如下5步完成:
(1)对指数操作:小指数向大指数看齐
(2)进行尾数加减运算
(3)规格化处理:尾数进行运算的结果必须变成规格化的浮点数,对于双符号位(就是使用00表示正数,11表示负数,01表示上溢出,10表示下溢出)的补码尾数来说,就必须是
001×××…×× 或110×××…××的形式
若不符合上述形式要进行左规或右规处理。
(4)舍入操作:在执行对阶或右规操作时常用“0”舍“1”入法将右移出去的尾数数值进行舍入,以确保精度。
(5)判结果的正确性:即检查指数是否溢出: 若指数下溢(移码表示是00…0),要置结果为机器0;
若指数上溢(超过了指数表示的最大值)置溢出标志。

浮点数乘除法

(1)指数运算:指数求和(乘法)或指数求差(除法)
    即  [Ex+Ey]移= [Ex]移+ [Ey]补
          [Ex-Ey]移= [Ex]移+  [-Ey]补
(2)浮点数的尾数处理:浮点数中尾数乘除法运算结果要进行舍入处理

更详细的描述可见:

What Every Computer Scientist Should Know About Floating-Point Arithmetic 

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html



No comments :

Post a Comment