正在准备考研复习,今天在看袁春风老师的计算机系统基础的时候讲到了布斯算法,于是去了解了一下,百度百科中的布斯算法部分还是讲得挺清楚的。下面是我的一些理解,如有错误欢迎指出。
乘法理解
对于最熟悉的十进制乘法很最基本的运算原理就是一个乘数乘以另一个乘数的个位、十位、百位···数字然后求和。比如==
123
×
456
=
123
×
6
+
123
×
5
×
10
+
123
×
4
×
1
0
2
123\times456 = 123\times6 +123\times5\times10+123\times4\times10^2
123×456=123×6+123×5×10+123×4×102==。放到二进制来看其实它也是这样的,多位数的乘法就是一个乘数乘上另一个乘数的各位求和。那么:
1101
×
1110
=
1101
×
1
×
2
3
+
1101
×
1
×
2
2
+
1101
×
1
×
2
1
+
1101
×
0
×
2
0
1101 \times 1110 = 1101\times1\times2^3+1101\times1\times2^2+1101\times1\times2^1+1101\times0\times2^0
1101×1110=1101×1×23+1101×1×22+1101×1×21+1101×0×20
布斯算法及原理
###原理
已经知道两个二进制数的乘法的实质是上面式子中那样了,假设例举的两个数1101
和1110
是无符号数,那么作乘法按照下面的式子来:
这里也体现了各位相乘最后求和的思想。按照上面直接来乘可以看到是要计算三位非0位与乘数的积然后求和,如果说一个乘数的非零位特别多1111111111110
,那么运算次数就会更多。而布斯算法很好地解决了这个问题。既然加法会乘这么多次那么用减法就好了。随遇上面的1110
可以写成10000-10
那么只用乘两次再作减就可以得到结果了,所以这就是布斯算法的原理。通过把求和转换成求差简化运算的次数。
具体算法
算法的基本思想是在乘数的末位添加一个"0"
,乘数中出现连续的"0"
和连续的"1"
处不进行任何运算;出现"10"
时,作减法;出现"01"
时作加法。每次只做一位乘法,因而每一步都右移一位。(来自于《计算机系统基础》)
依然以1101
和1110
为例(依然为无符号数),被乘数是1101
,乘数是1110
,我们知道:
1101
×
1110
=
1101
×
1
×
2
3
+
1101
×
1
×
2
2
+
1101
×
1
×
2
1
+
1101
×
0
×
2
0
=
1101
×
(
10000
−
10
)
1101 \times 1110 = 1101\times1\times2^3+1101\times1\times2^2+1101\times1\times2^1+1101\times0\times2^0=1101\times(10000-10)
1101×1110=1101×1×23+1101×1×22+1101×1×21+1101×0×20=1101×(10000−10)
上面的过程就体现了布斯算法的简化。由上面观察1110 -> 01110 -> (10000 - 10)
,把这个减法式子统一到一个位串里可以写成100(-1)0
。上面的减法是为了简化运算,选什么数来作减可以把原来为1
的位简化成0
呢?明显是高位比11...10...0
还高一位的100...00...0
减去高位与11...10...0
末位1
同位的00...10...0
序列而01
就标示出了一段连续1
的开头,而10
也标示出了一段连续1
的结尾,只是开头的地方是加,而结尾的地方是减去(不知道说清楚没有),对于连续的1
在转化过后明显都变成了0
所以这些位就不用理睬。
下面实际地计算一下这两个无符号数1101
和1110
,结果和中间结果取8位:
带符号数的计算
无符号数按照常规的方法可作如下计算(依然沿用前面的例子):
得到的答案是正确的,但是当1101
和1110
是带符号数的时候,这个答案就不对。难道用常规方法就不能进行带符号数的运算吗。当时在看这部分的时候,书上有一句话“对于带符号整数乘法,大多数处理器中会使用专门的补码乘法器来进行运算,一位补码乘法称为布斯乘法”,所以那个时候在还不太了解布斯乘法,所以误以为规算法无法进行带符号数的运算。其实后来发现,常规算法也是可以计算的,但是结果为什么不对,原因在于:以上两个数为例,进行乘法时中间数其实是乘数和被乘数被扩展成8位后进行各位相乘再截断为8位得到的,所以还是先看成无符号数把位填充满得到的是如下:
而之前算不对原因并非在于是否使用了布斯乘法,而是进行扩展的时候依然按照无符号数的方式进行了0扩展,得到的结果自然不对。
现在把上面的数看成符号数处理,1101 = -3, 1110 = -2
,所以正确计算后的结果应该是6
:
00000110 = 6
计算正确。但是这样的方式计算真的好长,因为非0位太多而要进行7次累加,换成布斯算法:
更加简单了,所以实际运算的时候使用的是补码乘法器运用布斯算法专门对带符号数进行运算。
布斯算法在乘法器中的应用
现在有两个带符号数a = -2
和b = -3
,他们在乘法器中的运算如下:
a
与b
补码的长度和为8位,又因为被乘数的末尾也可能是连续1
的结尾,所以添加一个附加位0
以能够作出10
标志的识别。所以首先设一个P
,长度为4 + 4 + 1 = 9
,还有A
和S
,初始值如下:
每一次都读取P
的末两位来判断现在是进行加操作还是减操作,加减操作过后每次还需要把P
向右移,此处是算数右移。通过上面的描述其实能对应到之前讲的算法。P
在10
时作减,前面说过作减可以通过加负数补码解决,也就是加上S
等同于作减法。P
在01
时作加,也就直接用P
加A
就行。分错开的初始值使得被乘数b
与乘数a
,不会被交叠而影响到对被除数中各位数的读取,而多次运算移位的过程其实就是手写运算时各位做乘,得到中间值然后累加的过程: