2.7 浮点运算
浮点数不能直接相加。下面以一个简单的8位尾数和一个未对齐的指数为例说明浮点运算,A = 1.0101001×24,B = 1.1001100×23。若要计算这两个数的乘积,应将尾数相乘,指数相加;即
A·B = 1.0101001×24×1.1001100×23
= 1.0101001×1.1001100×23+4
= 1.000011010101100×28.
现在来看看浮点加法。笔算时人们会像下面那样自动地将A与B的小数点对齐,
10101.001
- 1100.1100
100001.1110
然而,由于浮点操作数已经被表示为规格化形式,计算机在进行浮点加法时面临以下问题:
1.0101001×24
+1.1001100×23
为了对齐指数,计算机必须执行下面的步骤:
第1步,找出指数较小的那个数。
第2步,使两个数的指数相同。对于指数小的那个数,指数加几,就将尾数右移几位。
第3步,尾数相加(或相减)。
第4步,如果有必要,将结果规格化(后规格化)。
在这个例子里,A = 1.0101001×24且B = 1.1001100×23。B的指数比A的小,应将B的指数加1,使它与A的指数相等。由于指数加1会使B的值增加2倍,应将B的尾数除2,即将其右移1位。这两个操作使B的值保持不变,但被表示为0.110011×24。现在就可以将A与非规格化的B相加了。
A = 1.0101001×24
B = + 0.1100110×24
10.0001111×24
加法的结果不是规格化数,因为它的整数部分是102。因此需要对结果作规格化处理。尾数右移1位并将指数加1,得到1.00001111×25。结果的位数的精度为小数点后有8位数字,而A和B的尾数在小数点后只有7位数字。
图2-10给出了浮点加法运算的流程。对于这个流程图,以下几点需要注意。
1)因为指数有时与尾数位于同一个字中,在加法过程开始之前必须将它们分离开(解压缩)。
2)如果两个指数的差大于p+1,这里p为尾数的位数,较小的那个数由于太小而无法影响较大的数,结果实际上就等于较大的那个数。例如,1.1010×260+1.01×2-12的结果为1.1010×260,因为指数之差为72。
3)结果规格化时会检查指数,看它是否比最小指数小或比最大指数大,以分别检测指数下溢或上溢。指数下溢会导致结果为0,而指数上溢会造成错误,可能会要求操作系统介入处理。
舍入和截断误差
因为浮点运算可能引起尾数位数的增加,因此需要能够保持尾数位数不变的方法。最简单的技术叫作截断(truncation)。例如,将0.1101101截断为4位尾数的结果为0.1101。截断会产生诱导误差(induced error)(即误差是由施加在数上的操作计算所引起的),诱导误差是偏置的,因为截断后的数总是比截断前的小。
舍入(rounding)是一种更好的减少数的位数的技术。如果丢弃的位的值大于剩余数最低位的一半,则将剩余数的最低位加1。请考虑下面两个数在小数点后第4位上舍入的例子。
0.1101011 → 0.1101 删去的三位为011,什么也不做
0.1101101 → 0.1101+1 = 0.1110 删去的三位为101,因此加1
与截断相比,人们更青睐舍入,因为它更加精确并会引起非偏置的误差。截断总会使结果变小,带来系统性误差,而舍入有时会使结果减小,有时会使结果增大。舍入的主要不足在于它需要对结果进行一个额外的算术操作。
图2-11描述舍入机制。最简单的舍入机制是截断或向0舍入。“向最近的数舍入”方法,会选择距离该数最近的那个浮点数作为结果。“向正或负无穷大舍入”方法,会选择正或负无穷大方向上最近的有效浮点数作为结果。当要舍入的数位于两个连续浮点数的正中时,IEEE舍入机制会选择最低位为0的点(即向偶数舍入)。
具体实现时,浮点数使用3个专用位辅助完成舍入过程。一个m位的尾数可表示为1.m1m2…mmGRS,这里G为保护位(guard bit),用于暂时提高浮点数的精度;R为舍入位(rounding bit);用于辅助完成舍入,S为粘位(sticky bit)。粘位是R位右侧的所有位进行逻辑与运算后的结果,之所以这样称呼是因为一旦该位被置位(表明右边有一个或多个位为1)它就将保持为1。舍入算法根据以上3位确定舍入位的值。