定点数,顾名思义就是,小数点确定的数,当小数点确定在所有数的最右边,那就是整数运算,当确定在数的最左边,那就是小数运算,浮点数就是确定在尾数的最左边,并省去了整数部分的1。
定点数的乘法和除法都是仿照手写计算过程来实现并依据计算机的特性来改进的,我们今天先来看乘法运算。
手动计算
我们先来看看手动乘法计算过程:
假设二进制定点数,,计算他们的乘数可得:
我们可以看出,手算乘法是这样一个过程:
(1)从Y的第一位开始与X相乘,为0时得到相应位数的0,否则得到X。
(2)将上述每一位结果依次向左错位排列,可以看作左移。
(3)得到他们的和。
然后我们就得到了这两个数的乘积。
原码乘法
原码是浮点数尾数的表示形式,需要计算机能实现顶点原码小数的乘法运算。
原码乘法分两步:(1)有两个数的符号位异或得到乘积符号位;(2)计算乘积的数值位。乘积的数值部分为两个乘数的数值部分之积。
小数点不用管,计算机内部没有小数点的表示,只是约定了它的位置。因此我们可以将两个定点小数的数值部分之积看成是两个无符号数的乘积。
计算机进行无符号数的乘法计算时,采用了类似手算的方法。但为了提高效率,做了相应改进:
(1)每当将乘数Y的一位乘以被乘数得到后,就将它与前面的结果累加得到,我们把它叫做部分积。
这个改进没有等到全部计算完毕再进行移位和加和的操作,减少了保存每次的的开销。
(2)每次求得后,不是将它左移与前次部分积相加,而是将部分积右移一位,再以相应的高位与其相加。
(上文提到过,计算机中原码多用于表示浮点数的尾数部分,因此原码乘法中,小数乘法占了大多数。
计算机中的左移操作,对应于实际计算中的操作,右移操作对应于的操作,后者于小数计算更有利,而整数多用补码来进行计算,后文将讲到专门的布斯乘法来进行更便利的整数乘法)
(3)对乘数中为的位进行加法和右移运算,而对乘数中为的位只进行右移运算。
这样做的好处在于,如果按照手算操作,原本需要非常多位的储存与计算加法器,现在经过简化,只需要将的高n位进行相加,低位都不会改变,因此只需要n位的加法器就可以实现两个n位的无符号数的相乘,需要的存储容量也大大降低。
上述思想的数学推导如下:
其中有。
上述推导过程具有明显的递推公式,我们可以观察得出,其递推公式为:
我们可以设。
我们将上述推导过程的迭代过程归结如下:
(1)取乘数的最低位判断;
(2)若为1,则将上一步迭代部分积与X相加;若为0,则什么也不做。
(3)右移一位,产生本次部分积。
进行无符号数相加时,相加可能会产生进位,因而需要有一个专门的进位。
整个迭代过程从,经过n次“判断—加法—右移”循环,直到求出为止。假定每次循环在一个始终周期内开始,那么完成n位乘法就需要用n个时钟周期来完成。
32位无符号数乘法的逻辑结构图为:
其中,部分积与乘数Y是放在一个64位寄存器中的,Y的最低位判断相乘过后便没用了,右移一位舍弃它,P的右移也能留出空间,节省存储。
乘数寄存器Y一开始放置的是乘数,结束时放置的是64位乘积的低32位‘乘数寄存器P一开始放置的是,结束时放置的是64位乘积的高32位。
每次循环都要对进位位C、乘积寄存器P和乘数寄存器Y实现同步“右移”。
当乘数或被乘数中至少有一个全为0时,结果直接得0,不在进行乘法运算。
补码乘法运算
补码是机器中带符号整数的表现形式,需要计算机能实现补码乘法运算。
我们在计算时,常常将补码转换为原码形式,然后进行相应运算后再将结果转换为补码,但是这样太过繁琐。不骂的乘法也没有加法那样方便的特性,于是我们需要一个新的算法来计算不乏的乘法。
A.D.Booth提出了一种补码相乘算法,可以将符号位与数值位合在一起参与运算。于是称为“布斯算法”。
类似于原码,我们先进行利用补码形式的运算数学推导,观察得出其迭代或递推式:
假设,
根据补码的定义,我们可以得到的真值表达式为:
这里对y的第一项做一下解释。
我们都知道最开始的不添加任何符号的二进制数,也就是原码表示的无符号数,本来是只能表示~(n是用来表示二进制最大位数)的数,我们为了计算机的运算方便,才对二进制的表示形式做出种种规定。
而补码表示法,将正负数置于(n依然是最大位数)的系统之下,巧妙地利用了模的特性是计算机的运算变得更加简单快捷。
在模运算系统中,若、、满足关系:,则记为:,即A与B模M后余数相同,称为A与B同余。在一个模系统中,一个数与它除以模后得到的余数是等价的。
利用这个等价关系,计算机的前辈们把负数与其同余的正数等价起来,也就是说负数在模的系统下,跟这个数加得到的正数是等价的。这样补码就诞生了。
所以在补码中,如果这个数是一个负数,我们计算出它的十进制真值可以先取反加一再取负数,也可以直接把它当做原码表示法,计算出其正数真值,然后再减去,得到其表示为补码时所代表的的真值。
所以我们再回到y的真值表达式中来:
后面得到了它原码表示法时的十进制正数真值,当最高位为1时,它是负数,减去;为0时,它是正数,正数的原码表示法跟补码表示法是一样的,此时这一项为0,不影响结果正确。
我们在这个式子基础上进行归纳化简:
(设)
与无符号数乘法算法类似,我们可以得出:
与无符号数算法一样,我们可以不用考虑小数点的位置,只要最终的乘积约定好小数点位置就可以了。因此上述式子可以通过乘以来变换成下列形式:
展开观察,我们可以得到递推公式为:
由此公式又可以得到:
对于小数点的问题,比较刚归纳完的式子,我们可以知道,但是我们提过计算机中小数点的位置是可以随意约定的,因此我们在计算完毕之后将小数点的位置约定在乘积的最右边。
从上面的递推式,我们可以知道,布斯算法的部分积是由乘数中的连续两位确定的,因此我们可以得到它的规则为:
(1)若,;
(2)若,;
(3)若,。
代表右移
那么根据以上的分析,我们可以得出补码乘法运算规则如下:
(1)乘法最低位增加一位辅助位,即;
(2)根据的值,决定部分积还是,或者不加减;
(3)每次加减后算术右移一位,得到部分积;
(4)重复第(2)(3)步 n 次,得到结果。
布斯算法经过n次“判断-加减-右移”循环,当遇到,会直接跳过加法运算进行右移运算,因此效率较高。