乘法运算
(1)原码一位乘法
算法要点:(1)乘法通过加法和移位来实现。两个5位二进制数(最高位为符号位)相乘,共需要进行4次加法和4次移位。
(2)部分积总是先加上被乘数或零,然后右移1位得到新的部分积。
(3)部分积是加上被乘数还是加上零,取决于乘数中当前考虑的数位。该数位为1,则加上被乘数然后右移,否则直接右移。
(4)乘数中的数位一旦被考虑过,将不再需要,可以通过右移丢弃。
(5)部分积加上被乘数的过程中,数值最高位产生的进位可能会占据符号位。但是由于乘法中符号位是单独处理,所以被乘数,乘数和部分积都被认为是无符号位数,而且做完加法之后肯定要右移1位,因此这里出现的“进位占据符号位”的现象不算“溢出”,右移后符号位0将还原。
例:已知X=0.1010B,Y=-0.0111B,用原码一位乘法求X*Y=?
因为X=0.1010B,Y=-0.0111B,所以
[X]原=0.1010,X*=0.1010,x0=0;
[Y]原=1.0111,Y*=0.0111,y0=1;
部分积 乘数 注释
0.0000 0111 此时乘数为0111,开始时,部分积Z0=0;
+0.1010 乘数中当前考虑的数位为1,加上X*
0.1010
0.0101 -> (0右移) 0 011 (1右移舍去) 右移一位得新部分积Z1
+0.1010 乘数中当前考虑的数位为1,加上X*
0.1111
0.0111 -> (1右移) 10 01 (1右移舍去) 右移一位得新部分积Z2
+0.1010 乘数中当前考虑的数位为1,加上X*
1.0001
0.1000 -> (1右移) 110 0 (1右移舍去) 右移一位得新部分积Z3
+0.0000 乘数中当前考虑的数位为0,加上0
0.1000
0.0100 0110 右移一位得新部分积Z4
[X*Y]原 的符号位=x0⊕y0=0⊕1=1
所以X* * Y* =0.01000110 ,则[X*Y]原=1.01000110,X*Y=-0.01000110
原码一位乘法的实现虽然比较简单,但是由于计算机都是采用补码来进行加,减运算,如果为了做乘法运算而将操作数从补码转换成原码,运算结束后再从原码转换成补码,这样就增加了许多操作步骤,延迟了计算时间。为此,人们又研究了补码乘法方法,实现了基于补码的乘法器,这样就进一步提高了乘法运算的效率。
(2)补码一位乘法
补码一位乘法是把乘数Y补码的符号位设成0,当做一个正数,与被乘数补码相乘。乘法运算的步骤与原码乘法相同。乘积出来后,如果Y是负数,则加上[-X]补得到[X*Y]补;否则乘积就直接等于[X*Y]补。这样的补码一位乘法也称校正法。
例:已知X=0.1010B,Y=-0.0111B,用校正法求X*Y=?
被乘数补码为[X]补=0.1010B,乘数补码为[Y]补=1.1001。由于Y是负数,所以将其符号位去掉,故参与运算的乘数是0.1001。乘积出来后加上[-X]补进行校正。[-X]补=1.0110。
考虑到运算时可能会出现部分积的绝对值大于1的情况,所以被乘数和部分积采用双符号位。
部分积 乘数 注释
00.0000 1001 此时乘数为1001,开始时,部分积Z0=0;
+00.1010 乘数中当前考虑的数位为1,加上[X]补
00.1010
00.0101 -> (0右移) 0 100 (1右移舍去) 右移一位得新部分积Z1
+00.0000 乘数中当前考虑的数位为0,加上0
00.0101
00.0010 -> (1右移) 10 10 (0右移舍去) 右移一位得新部分积Z2
+00.0000 乘数中当前考虑的数位为0,加上0
00.0010
00.0001 -> (0右移) 010 1 (0右移舍去) 右移一位得新部分积Z3
+00.1010 乘数中当前考虑的数位为1,加上[X]补
00.1011
00.0101 -> (1右移) 1010 (1右移舍去) 右移一位得新部分积Z4
+11.0110 加上[-X]补进行校正
11.1011 1010
结果为[X*Y]补=1.10111010,所以X*Y=-0.01000110B。
采用补码进行乘法,乘积的符号是在计算中自然得到的,这是补码运算的一个共同特点,也是与原码乘法的一个重要区别。
(3)布斯算法
上述校正法的运算过程与乘数的符号有关。虽然可以将被乘数与乘数交换位置,使得乘数尽可能为正,以避免校正操作。但是当被乘数与乘数均为负数时,校正操作就不可避免了,所以校正法的控制逻辑比较复杂。为此,英国计算机专家布斯(A.D.Booth)于1956年提出了不用考虑操作数符号,可以用统一的规则进行计算的“布斯算法”。
yi-1yi | yi-yi-1 | 操作 |
00 | 0 | 加上0,即直接右移一位 |
01 | 1 | 加上[X]补,再右移一位 |
10 | -1 | 加上[-X]补,再右移一位 |
11 | 0 | 加上0,即直接右移一位 |
例:已知X=0.1010B,Y=-0.0111B,用布斯算法求X*Y=?
被乘数补码为[X]补=0.1010B,乘数补码为[Y]补=1.1001,校正数[-X]补=1.0110。
部分积 乘数 附加位 注释
00.0000 1100 1 0 此时乘数为11001,开始时,部分积Z0=0;
+11.0110 yi-1 yi yi-1yi为10,加上[-X]补
11.0110
11.1011 -> (0右移) 0 110 0 1 右移一位得新部分积Z1
+00.1010 yi-1yi为01,加上[X]补
00.0101
00.0010 -> (1右移) 10 11 0 0 右移一位得新部分积Z2
+00.0000 yi-1yi为00,加上0
00.0010
00.0001 -> (0右移) 010 1 1 0 右移一位得新部分积Z3
+11.0110 yi-1yi为10,加上[-X]补
11.0111
11.1011 -> (1右移) 1010 1 1 右移一位得新部分积Z4
+00.0000 yi-1yi为11,加上0
11.1011 1010 1 第5步运算结束后,不再右移
除法运算
(1)原码恢复余数除法
原码除法的特点是:符号位单独处理,操作数的绝对值相除。
例:设被除数X=+0.1010B,除数Y=-0.1101B。求X/Y=?
[X]原=0.1010B,[Y]原=1.1101B,所以商的符号等于0⊕1=1。
记X的绝对值为X*=0.1010B,Y的绝对值为Y*=0.1101B。则商的绝对值等于X*/Y*。
由于要做“余数(被除数)减去除数”的操作,而在计算机中这个操作是通过“余数(被除数)加上负的除数的补码”来完成的,所以给出[-Y*]补。
因为[Y*]补=0.1101B,所以[-Y*]补=1.0011B。
操作 被除数(当前余数) 填商 注释
00.1010
加上 [-Y*]补 +11.0011
11.1101 0 余数为负,上商0
加上[Y*]补 + 00.1101
00.1010 恢复余数
左移1位 01.0100 0
加上 [-Y*]补 +11.0011
00.0111 01 余数为正,上商1
左移1位 00.1110 01
加上 [-Y*]补 +11.0011
00.0001 011 余数为正,上商1
左移1位 00.0010 011
加上 [-Y*]补 +11.0011
11.0101 0110 余数为负,上商0
加上[Y*]补 +00.1101
00.0010 恢复余数
左移1位 00.0100 0110
加上 [-Y*]补 +11.0011
11.0111 01100 余数为负,上商0
加上[Y*]补 +00.1101
00.0100 恢复余数(最终余数)
所以X*/Y*的商是0.1100B,余数为0.0100B*2^(-4)=0.00000100B
由于在这个原码算法中,一旦上商0。就需要恢复余数后才能计算下一位商。故称其为“恢复余数除法”。由于它在计算过程中需要恢复余数,所以运算速度变慢,而且恢复余数的次数事先是未知的,所以运算步数不能预先确定,这会使控制逻辑变得复杂。
(2)原码加减交替除法
操作 被除数(当前余数) 填商 注释
00.1010
加上 [-Y*]补 +11.0011 减去除数
11.1101 0 余数为负,上商0
左移1位 11.1010 0
00.0111 01 余数为正,上商1
左移1位 00.1110 01
加上 [-Y*]补 +11.0011 减去除数
00.0001 011 余数为负,上商0
左移1位 00.0010 011
加上 [-Y*]补 +11.0011 减去除数
11.0101 0110 余数为负,上商0
左移1位 10.1010 0110
加上[Y*]补 +00.1101 加上除数
11.0111 01100 余数为负,上商0
加上[Y*]补 +00.1101 加上除数
00.0100 恢复余数(最终余数)
所以X*/Y*的商是0.1100B,余数为0.0100B*2^(-4)=0.00000100B
对于计算机的定点小数除法而言,商也必须是定点小数。这就要求被除数的绝对值必须小于除数的绝对值、也就是说,第一次上商必须是0,否则视为“溢出”。
定点整数同理。