补码一位乘法-一般乘法与Booth的证明与原理

补码一位乘法

为什么要使用补码乘法?

在计算机中,使用一般乘法的话,对符号位还要重新进行异或操作,这样会大大降低运算速度,而使用补码乘法运算,就可以找到一种通用的解法来解决符号位的重复计算,而将符号位作为数字一起带入运算器进行计算

补码一位乘法规则

首先说明一下,为了便于证明,下面的证明都是在小数的基础上进行的,小数证明以后便可以直接推广整数

假设被乘数为 [ x ] 补 [x]_补 [x]
[ x ] 补 = x 0 x 1 x 2 x 3 . . . x n [x]_补=x_0x_1x_2x_3...x_n [x]=x0x1x2x3...xn
乘数为 [ y ] 补 [y]_补 [y]
[ y ] 补 = y 0 y 1 y 2 y 3 . . . y n [y]_补=y_0y_1y_2y_3...y_n [y]=y0y1y2y3...yn

两者均为任意的符号位,则有补码乘法公式:
[ x ∗ y ] 补 = [ x ] 补 ∗ y [x*y]_补=[x]_补*y\\ [xy]=[x]y
而由补码与其真值的关系:
[ y ] 补 = 2 + y    ( m o d    2 ) y = − y 0 + ∑ i = 1 n y i 2 − i [y]_补=2+y\ \ (mod\ \ 2)\\ y=-y_0+\sum_{i=1}^ny_i2^{-i} [y]=2+y  (mod  2)y=y0+i=1nyi2i
(这个还是比较好证明的,对于正数,前面+2直接溢出了,所以还是等于y,而对于负数,第一次+1相当于是进行了一次模1运算,使其数值位跟补码一致,第二次+1相当于纠正了符号位为负数)

我们可以得到:
[ x ∗ y ] 补 = [ x ] 补 ∗ ( − y 0 + ∑ i = 1 n y i 2 − i ) [x*y]_补=[x]_补*(-y_0+\sum_{i=1}^ny_i2^{-i})\\ [xy]=[x](y0+i=1nyi2i)
在此我们可以对以上的补码乘法公式进行证明
    [ x ] 补 = x 0 x 1 x 2 . . . x n = ( 2 x 0 + x )    m o d    2 = ( 2 n + 1 x 0 + x )    m o d    2     [ y ] 补 = 0 y 1 y 2 . . . y n = y ∴     [ x ] 补 ∗ y = ( 2 n + 1 x 0 + x ) y = 2 n + 1 x 0 y + x y ∵     y = ( − y 0 + ∑ i = 1 n y i 2 − i ) ∴     [ x ] 补 ∗ y = ( − 2 n + 1 x 0 y 0 + 2 x 0 ∑ i = 1 n y i 2 n − i ) + x y    ( m o d    2 )                  = 2 + x y     ( m o d    2 ) 【 这 里 要 根 据 模 2 性 质 进 行 推 导 】                  = [ x y ] 补 \begin{aligned} &\ \ \ [x]_补=x_0x_1x_2...x_n=(2x_0+x)\ \ mod\ \ 2=(2^{n+1}x_0+x)\ \ mod\ \ 2\\ &\ \ \ [y]_补=0y_1y_2...y_n=y\\ \therefore&\ \ \ [x]_补*y=(2^{n+1}x_0+x)y=2^{n+1}x_0y+xy\\ \because&\ \ \ y=(-y_0+\sum_{i=1}^ny_i2^{-i})\\ \therefore&\ \ \ [x]_补*y=(-2^{n+1}x_0y_0+2x_0\sum_{i=1}^ny_i2^{n-i})+xy\ \ (mod\ \ 2)\\ &\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =2+xy \ \ \ (mod\ \ 2)【这里要根据模2性质进行推导】\\ &\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =[xy]_补 \end{aligned}    [x]=x0x1x2...xn=(2x0+x)  mod  2=(2n+1x0+x)  mod  2   [y]=0y1y2...yn=y   [x]y=(2n+1x0+x)y=2n+1x0y+xy   y=(y0+i=1nyi2i)   [x]y=(2n+1x0y0+2x0i=1nyi2ni)+xy  (mod  2)                =2+xy   (mod  2)2                =[xy]
其实由上面的共识我们可以很容易得到公式:
[ x y ] 补 = [ x ] 补 ( 0 y 1 y 2 . . . y n ) − [ x ] 补 ∗ y 0 [xy]_补=[x]_补(0y_1y_2...y_n)-[x]_补*y_0 [xy]=[x](0y1y2...yn)[x]y0
使用这样的公式来求补码乘法,我们称之为校正法

对了,记住在使用校正法时应该是使用算数右移,即移动的时候ACC寄存器中补位的数应该跟ACC寄存器中的第一位一致

为什么要用Booth算法?

在一般的补码乘法中,我们进行加法运算的次数和加法中1的个数存在直接关系,而对于乘数中1比较多的情况,如果还是采用一般的补码乘法运算显然就比较低效,因此我们使用的Booth算法,这样只有在前后两位产生01的变化时才需要进行加法(或者减法,但是计算机中的减法其实就是加法,所以不用细究)运算。这样就可以大大提高运算效率了

Booth算法规则

image-20220706202430006

第一,我们需要知道补码的运算规律是使用n轮加法与移位,最后在多进行一次加法,关于为什么要多一次加法,如果大家使用乘法分配律来理解就很容易知道了,因为最后一定会加一个数,不要问为什么,只要理解了乘法分配律就知道了

其次,补码一位乘法中,每次加法加的可能是 0 、 [ x ] 补 、 [ − x ] 补 0、[x]_补、[-x]_补 0[x][x],这又与原码移位算法不一样了

还有,对于补码一位乘法,每次移位只能是算数移位,也就是在前面补位时,补的位和符号位一样(只有第一位才是符号位嗷)

最最最关键的一点,在补码一位运算中,符号位也会参与运算!!!

符号位参与运算❓

大家一定会疑惑,为什么符号位也能参与运算?

原因很简单,在补码中,符号位并不是真的没有意义的,因为我们会发现,在真值跟补码的关系中,我们是可以找到一种方式将他们联系起来的

补码只对负数存在特别之处,但是对于正数跟原码是没有区别的,我们会发现,比如-1,他的补码其实就是 11111111 11111111 11111111

当我们对他进行+1操作以后,它就会变成100000000,但是由于最大表示位只有八位(在例子中),所以最后的结果会默认变成00000000也就是0

所以说,我们可以认为对于负数t来说,补码就是 2 n + t 2^n+t 2n+t的二进制位(要去掉超出的位数,n为最大位数),而我们会发现,对于0和正数来说,这个规律同样适用

所以我们会发现,这个所谓的符号位其实也可以当作数来计算,但是它同样担负着确认正负的重要职责,所以在转化的时候,我们只会将符号位转化为正负,而不会转化成数值

但是我们在计算过程中其实可以将它当作数值来看待,反正超出的位对我们没有什么影响(电路自动进行模运算)


运算法则

首先,在运算过程中,我们在MQ中会多使用一位来作为辅助位,以决定我们当前这一步到底进行加法还是减法运算,也因为MQ多了一位,所以其他寄存器也要跟着多添加一位

image-20220706205920327

运算法则如上图,其实翻译过来就是,算上辅助位,

当在MQ寄存器中最后两位是01时就进行加x的补码,再进行右移位

当是10时就进行减x的补码的操作,也就是加 [ − x ] 补 [-x]_补 [x]的操作,再进行右移位

其余的时候只要直接进行右移位就行了

WHY?

这里我不确保我能讲的明白,其实理解上就是一种乘法分配律,如果看不懂的可以看这篇博客

对于任意一个数,我们在小学的时候经常会学习使用一种办法化繁为简,比如计算 9 ∗ 99 9*99 999时,我们会将其拆分成 9 ∗ ( 100 − 1 ) 9*(100-1) 9(1001)

这里我们其实用的是一个道理,比如对于010111110,我们可以拆分成(100000000-01000000+001000000-000000010)

这样我们就可以使用更少的加法来简化运算了,可以观察到,本来我们要使用6次加法运算,现在我们只需要使用4次加法运算即可(计算机中减法也是通过加法完成的)

这里其实在数学上也是存在证明的,对于一个数A来说,我们可以写成下面的形式:
A = − x n − 1 ∗ 2 n − 1 + x n − 2 ∗ 2 n − 2 + . . . + x 0 ∗ 2 0 = − x n − 1 ∗ 2 n − 1 + x n − 2 ∗ ( 2 n − 1 − 2 n − 2 ) + . . . + x 0 ∗ ( 2 1 − 2 0 ) = 2 n − 1 ∗ ( x n − 2 − x n − 1 ) + 2 n − 2 ∗ ( x n − 3 − x n − 2 ) + 2 1 ( x 0 − x 1 ) + 2 0 ( 0 − x 0 ) 这 里 我 们 不 妨 虚 构 出 一 个 x − 1 = 0 , 以 便 得 到 通 用 结 论 ∴ 原 式 = ∑ i = 1 n 2 i − 1 ∗ ( x i − 2 − x i − 1 ) \begin{aligned} A&=-x_{n-1}*2^{n-1}+x_{n-2}*2^{n-2}+...+x_0*2^0\\ &=-x_{n-1}*2^{n-1}+x_{n-2}*(2^{n-1}-2^{n-2})+...+x_0*(2^1-2^0)\\ &=2^{n-1}*(x_{n-2}-x_{n-1})+2^{n-2}*(x_{n-3}-x_{n-2})+2^1(x_0-x_1)+2^0(0-x_0)\\ 这&里我们不妨虚构出一个x_{-1}=0,以便得到通用结论\\ \therefore原式&=\sum_{i=1}^n2^{i-1}*(x_{i-2}-x_{i-1}) \end{aligned} A=xn12n1+xn22n2+...+x020=xn12n1+xn2(2n12n2)+...+x0(2120)=2n1(xn2xn1)+2n2(xn3xn2)+21(x0x1)+20(0x0)x1=0,便=i=1n2i1(xi2xi1)
由此我们得证上面式子的正确性

image-20220706210628682

于是我们便可以直接使用上面的结论进行Booth算法的计算,这里我直接饮用了王道的ppt,大家可以试着自己算一下

如果说实在想不起来Booth算法的规则,我们也可以使用化繁为简的方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个老蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值