浮点数运算

      今天学习了浮点数运算(加减乘除)。浮点数运算主要包括两部分:指数运算和尾数运算。在IEEE754标准下,指数运算就是阶码的运算,类似于无符号数运算。尾数运算是原码运算。之前一直很疑惑为什么前面的教材在介绍原码运算(加减乘除)所举的例子都是小数运算。现在猜想那部分内容可能只是为了浮点数运算做铺垫,这里才是主要的内容。(当然知识是不分重点的,但考试分)。下面就来详细介绍下浮点数运算的过程吧!另外本文使用的浮点数标准均为IEEE754结构,即单精度数由1位符号位,8位指数位,23位尾数位共计32位组成。

一、浮点数的加减运算:

       浮点数的加减运算分为5个步骤:对阶、尾数相加、尾数规格化、尾数舍入处理、溢出判断处理。下面详细介绍:

1. 对阶:

      所谓对阶,就是让两个操作数阶数相同,以便进行加减。实现的方式是对较小数的尾数进行右移操作。对阶的原则是向高阶看齐。计算公式为:
浮点数运算
      当结果大于0说明被加数(被减数)阶数高,则对加数(减数)进行移位对阶。小于0则反之改变被加数(被减数)。

2. 尾数加减:

      将两个操作数的尾数相加减。值得注意的是:在IEEE754标准中,对于规格化数来说在小数点前有一位隐藏位1,在加减过程中需要把它还原到尾数中。尾数加减的实质是原码的加减,对于原码加减的规则如下图所示:

浮点数运算

3. 尾数规格化:

      加减完成的尾数形式未必满足IEEE754对于尾数的要求,即保留23位,小数点在第一个1之后。需要对尾数进行左规和右规,下面介绍一下左规和右规。

      左规:将尾数向左移,用于清楚第一个1前面出现的0。左规伴随着阶码减少,在左规过程中要检测阶码是否发生下溢,即阶码达到最小值(0000 0000)。

      右规:将尾数向右移,用于两数相加后出现向高位进位的情况。因为两数相加最多进一位,所以右规最多一位。右规伴随着阶码的增加,在右规过程中要检测阶码是否发生上溢,即阶码达到最大值(1111 1111)。

4. 尾数的舍入处理:

      在对阶和右规的时候,最右边的数字会被移出。为了保证最后计算的精度,把这些数字在过程中保存,等到最后进行舍入。也就是我上文提到的附加位。有两个问题值得注意:

      1) 保留多少附加位合适?

      2)最终对附加位怎么进行舍入?

      在IEEE754中保留了保护位,舍入位,粘位三位作为附加位。同时对于IEEE754来说最后附加位的舍入,有如下规则:
浮点数运算

5. 溢出判断:

      在浮点数中是以阶码的溢出与否来作为评判标准的。单精度溢出分为上溢(指数大于等于127)和下溢(指数小于等于-126)。

      插一句:“之前一直以为下溢的指数是-149,这个数字来源于-126再把所有的尾数向右移,当到达-149时刚刚好所有尾数全部为零,即表示零。这个误区在于没有正确的区分规格化数和非规格化数。对于规格化数而言,下溢就是-126,所以规格化数表示的最小值为1.00…乘2的-126次方,而0~0.111…乘2的-126次方就是非规格化数表示的范围。-149正是非规格化数表示的最小范围。这里贴一张图,更加便于理解。

浮点数运算
      下面直接粘贴一个书上的实例,对以上过程进一步加深了解:
浮点数运算

二、浮点数乘除运算:

      浮点数乘除和定点数乘除相同,在正式运算前会对操作数进行预处理。对于乘法如果有一个操作数为0则结果为0。对于浮点数除法,若被除数为0,则结果为0。除数为0分两种情况,第一种是被除数非零,第二种是被除数为0。下面着重介绍一下两种除数为0:
      除数为0,被除数不为0:
         结果为无穷大。在IEEE 754标准下就是阶码全为1,尾数全为0。C语言输出如下图:
浮点数运算
      除数为0,被除数为0:
         结果是NAN(not a number)。在IEEE 754标准下就是阶码全为1,尾数非0。在C语言中输出如下图:
浮点数运算
      注:在Windows系统下,-1.#IND00即代表nan,Linux系统下会输出nan。

      下面详细介绍无特殊情况浮点数的乘除运算:

      浮点数乘除运算公式如下图:
浮点数运算

   1.浮点数的乘法:

         点数的乘法运算主要分为四步:尾数相乘指数相加、尾数规格化、尾数舍入处理、溢出处理判断。

       1)尾数相乘,指数相加:

         尾数相乘即为原码相乘,这个具体的过程请参考另一篇文章:定点数运算(于文末给出网址)。值得注意的是,对于规格化浮点数要记得恢复隐藏位。指数相加可以直接运用移码的计算方法:

      2)尾数规格化:

         对于两个操作数的尾数一定都是大于1的(隐藏位导致),所以最终得到的结果,小数点前会有两位共三种情况(01,11,10)。若为01则不需规格化,11和10则需右规一位。注意对于IEEE754标准浮点数乘法不需要左规。

      3)尾数舍入处理:

         两个小数相乘,尾数自然更多,但位置是有限的,需要对尾数进行舍入,具体的舍入规则参照浮点数加减的舍入规则即可。

      4)溢出处理判断:

         乘法的溢出有两种可能:阶码相加减时,以及尾数右规时。右规与上文相同,下面介绍一下阶码溢出的判断标准:
浮点数运算
      注:Eb是最终的结果,EX和EY是操作数的指数值。

   2.浮点数除法:

      浮点数除法大致分为4步:尾数相除阶相减、尾数规格化、尾数舍入、溢出判断处理。由于除法大部分与乘法相似,所以此处只列出不同部分。

     在尾数相除阶相减过程中,尾数除法也在上文引用那篇文章中有具体介绍。阶码相减的运算公式如下:
浮点数运算
      在尾数规格化步骤中:当除法运算完成后,若小数点前为0,则需进行左规以保证小数点前具有隐藏位1。

      对于除法阶码溢出判断的规则如下:
浮点数运算
      注:Eb为最终结果指数,EXEY为操作数指数。

本篇文章对于浮点数运算进行了介绍,因为作者水平有限,可能某些地方理解错误,请高手不吝赐教,批评指正,谢谢!