补码乘法运算的原理

补码乘法运算的原理

补码的出现统一了计算机运算中的加减法操作,那对于补码的乘法该如何操作呢?

补码表示法

  • 纯小数补码的定义

[ x ] 补 = { x 1 > x ≥ 0 2 + x 0 > x ≥ − 1 ( m o d 2 ) [x]_{补}=\left\{ \begin{aligned} x &&&&& 1> x \geq0 \\ 2+x &&&&& 0>x \geq -1 \end{aligned} \right.(mod \quad 2) [x]={x2+x1>x00>x1(mod2)
比如两个小数分别为
x 1 = − 0.0010 x 2 = + 0.1101 x_1 = -0.0010 \\ x_2=+0.1101 x1=0.0010x2=+0.1101
则根据补码表示法
[ x 1 ] 补 = 2 + x 1 = 2 + ( − 0.0010 ) = 1.1110000 [ x 2 ] 补 = x 2 = 0.1101000 [x_1]_{补}=2+x_1=2+(-0.0010)=1.1110000\\ [x_2]_{补}=x_2=0.1101000 [x1]=2+x1=2+(0.0010)=1.1110000[x2]=x2=0.1101000
以上字长均为八位。

  • 纯整数的补码定义

[ x ] 补 = { x 2 n > x ≥ 0 2 n + 1 + x 0 > x ≥ − 2 n ( m o d 2 ) [x]_{补}=\left\{ \begin{aligned} x &&&&& 2^n> x \geq0 \\ 2^{n+1}+x &&&&& 0>x \geq -2^n \end{aligned} \right.(mod \quad 2) [x]={x2n+1+x2n>x00>x2n(mod2)
比如两个整数分别为:
x 1 = 1101 x 2 = − 0011 x_1=1101 \\ x_2 = -0011 x1=1101x2=0011
根据补码表示法
[ x 1 ] 补 = x 1 = 1101 [x_1]_{补}=x_1 =1101 [x1]=x1=1101
[ x 2 ] 补 = x 2 + 2 8 = 10000000 + ( − 0011 ) = 11111101 [x_2]_{补}=x_2+2^8=10000000+(-0011)=11111101 [x2]=x2+28=10000000+(0011)=11111101

定点补码一位乘法——校正法

先给公式:
对于纯小数
[ x ] 补 = x 0 . x 1 x 2 … x n [ y ] 补 = y 0 . y 1 y 2 … y n [x]_{补}= x_0.x_1x_2\dots x_n \\ [y]_{补}=y_0.y_1y_2\dots y_n [x]=x0.x1x2xn[y]=y0.y1y2yn
其中 x 0 x_0 x0 y 0 y_0 y0分别是被乘数与乘数 x x x y y y的符号位
[ x ∗ y ] 补 = x 补 ∗ ( 0. y 1 y 2 … y n ) − [ x ] 补 ∗ y 0 [x*y]_{补}=x_补*(0.y_1y_2\dots y_n)-[x]_{补}*y_0 [xy]=x(0.y1y2yn)[x]y0
下来证明这一结论:

  1. 首先考虑乘数 y y y为正数的情形
    • 假定被乘数 x x x也为正数,则此时是两个正数相乘。
      对于正数,它的原码,补码,反码是相同的,所以根据原码乘法的正确性可以得到这种情形也是正确的。
    1. 假定被乘数 x x x是负数,
      则有
      [ x ] 补 = x 0 . x 1 x 2 … x n = 2 + x = 2 n + 1 + x [ y ] 补 = y 0 . y 1 y 2 … y n = y [x]_{补}=x_0.x_1x_2\dots x_n=2+x = 2^{n+1}+x \\ [y]_{补}=y_0.y_1y_2\dots y_n=y [x]=x0.x1x2xn=2+x=2n+1+x[y]=y0.y1y2yn=y
      这一步中的 2 + x = 2 n + 1 + x 2+x=2^{n+1}+x 2+x=2n+1+x是根据mod 2的性质得到的,对于纯小数无论是+2还是+4或者是加 2 n 2^n 2n都只能保留小数点前一位的符号位,因此这些结果都是相同的。
      所以有
      [ x ] 补 ∗ [ y ] 补 = [ x ] 补 ∗ y = ( 2 n + 1 + x ) ∗ y = 2 n + 1 ∗ y + x ∗ y [x]_{补}*[y]_{补}=[x]_补*y\\=(2^{n+1}+x)*y=2^{n+1}*y+x*y [x][y]=[x]y=(2n+1+x)y=2n+1y+xy
      其中
      y = 0. y 1 y 2 … y n = ∑ i = 1 n y i ∗ 2 − i y=0.y_1y_2\dots y_n=\sum_{i=1}^{n}y_i*2^{-i} y=0.y1y2yn=i=1nyi2i
      所以
      2 n + 1 ∗ y = 2 ∑ i = 1 n y i ∗ 2 n − i 2^{n+1}*y=2\sum_{i=1}^{n}y_i*2^{n-i} 2n+1y=2i=1nyi2ni
      式中的 n − i > = 0 n-i>=0 ni>=0因此
      ∑ i = 1 n y i ∗ 2 n − i \sum_{i=1}^{n}y_i*2^{n-i} i=1nyi2ni是一个整数。
      所以
      2 n + 1 ∗ y 2^{n+1}*y 2n+1y是一个偶数。
      所以
      [ x ] 补 ∗ [ y ] 补 = [ x ] 补 ∗ y = ( 2 n + 1 + x ) ∗ y = 2 n + 1 ∗ y + x ∗ y = 2 + x y = [ x ∗ y ] 补 [x]_{补}*[y]_{补}=[x]_补*y\\=(2^{n+1}+x)*y=2^{n+1}*y+x*y\\=2+xy=[x*y]_补 [x][y]=[x]y=(2n+1+x)y=2n+1y+xy=2+xy=[xy]
      这一步是根据x*y是负数所以有 2 + x y = [ x ∗ y ] 补 2+xy=[x*y]_补 2+xy=[xy]
  2. 接着考虑乘数 y y y为负数的情形
    在上一步中,我们证明了y是正数的情况,在证明y是负数是自然想到应该向y是正数靠拢。
    考虑到:
    [ y ] 补 = y 0 . y 1 y 2 … y n = y + 2 [y]_补=y_0.y_1y_2\dots y_n=y+2 [y]=y0.y1y2yn=y+2
    所以有
    y = [ y ] 补 − 2 = 1. y 1 y 2 … y n − 2 = 0. y 1 y 2 … y n − 1 y=[y]_补-2=1.y_1y_2\dots y_n-2=0.y_1y_2\dots y_n -1 y=[y]2=1.y1y2yn2=0.y1y2yn1
    此时我们发现y被表示成一个正数的补码与1的差值的形式,那么我们就可以用第一问的结论:
    [ x ∗ y ] 补 = [ x ∗ ( 0. y 1 y 2 … y n ) ] 补 + [ − x ] 补 = [ x ] 补 ∗ ( 0. y 1 y 2 … y n ) + [ − x ] 补 [x*y]_{补}=[x*(0.y_1y_2\dots y_n)]_补+[-x]_补\\=[x]_补*(0.y_1y_2\dots y_n)+[-x]_补 [xy]=[x(0.y1y2yn)]+[x]=[x](0.y1y2yn)+[x]
    结合第一种情形
    [ x ∗ y ] 补 = [ x ] 补 ∗ ( 0. y 1 y 2 … y n ) [x*y]_{补}=[x]_补*(0.y_1y_2\dots y_n) [xy]=[x](0.y1y2yn)
    将两种情况统一,可得到:
    [ x ∗ y ] 补 = [ x ] 补 ∗ ( 0. y 1 y 2 … y n ) − [ x ] 补 ∗ y 0 [x*y]_{补}=[x]_补*(0.y_1y_2\dots y_n)-[x]_{补}*y_0 [xy]=[x](0.y1y2yn)[x]y0
    之所以称为校正法就是因为对于被乘数小于0的情形需要加上 [ − x ] 补 [-x]_补 [x]加以修正。
    因为校正法需要首先判断乘数的正负,再确定是否需要加上 [ − x ] 补 [-x]_补 [x]加以修正,在这个过程中乘数的符号位不参与运算,且需要判断,所以在校正法的基础上提出了Booth乘法

Booth乘法

[ x ∗ y ] 补 = [ x ] 补 ( 0. y 1 y 2 … y n ) − [ x ] 补 ∗ y 0 [x*y]_{补}=[x]_{补}(0.y_1y_2\dots y_n)-[x]_{补}*y_0 [xy]=[x](0.y1y2yn)[x]y0
[ x ∗ y ] 补 = [ x ] 补 ( 0. y 1 y 2 … y n ) − [ x ] 补 ∗ y 0 = [ x ] 补 ∗ ( − y 0 + y 1 2 − 1 + y 2 2 − 2 + … y n ∗ 2 − n ) = [ x ] 补 ∗ [ − y 0 + ( y 1 − y 1 ∗ 2 − 1 ) + ( y 2 ∗ 2 − 1 − y 2 ∗ 2 − 2 ) …   ] = [ x ] 补 ∗ [ ( y 1 − y 0 ) + ( y 2 − y 1 ) ∗ 2 − 1 … ( y n − y n − 1 ) ∗ 2 − ( n − 1 ) + ( 0 − y n ) ∗ 2 − n ] \begin{aligned} [x*y]_{补} &= [x]_{补}(0.y_1y_2\dots y_n)-[x]_{补}*y_0 \\ &= [x]_{补}*(-y_0+y_12^{-1}+y_22^{-2}+\dots y_n*2^{-n})\\ &= [x]_{补}*[-y_0+(y_1-y_1*2^{-1})+(y_2*2^{-1}-y_2*2^{-2})\dots]\\ &= [x]_{补}*[(y_1-y_0)+(y_2-y_1)*2^{-1}\dots (y_n-y_{n-1})*2^{-(n-1)}+(0-y_n)*2^{-n}] \end{aligned} [xy]=[x](0.y1y2yn)[x]y0=[x](y0+y121+y222+yn2n)=[x][y0+(y1y121)+(y221y222)]=[x][(y1y0)+(y2y1)21(ynyn1)2(n1)+(0yn)2n]
所以我们根据上式可以得到Booth乘法的递推公式:
[ z 0 ] C = 0 [ z 1 ] C = 2 − 1 { ( y n + 1 − y n ) [ x ] C + [ z 0 ] C } ⋮ [ z n ] C = 2 − 1 { ( y 2 − y 1 ) [ x ] C + [ z n − 1 ] C } \begin{aligned}&[z_0]_{C} = 0 \\ &[z_1]_{C} = 2^{-1}\{(y_{n+1}-y_n)[x]_C+[z_0]_{C}\}\\ & \vdots\\ &[z_n]_C= 2^{-1}\{(y_2-y_1)[x]_C+[z_{n-1}]_C\} \end{aligned} [z0]C=0[z1]C=21{(yn+1yn)[x]C+[z0]C}[zn]C=21{(y2y1)[x]C+[zn1]C}
故最终的结果为:
[ x ∗ y ] 补 = [ z n ] 补 + ( y 1 − y 0 ) [ x ] 补 [x*y]_{补}=[z_n]_{补}+(y_1-y_0)[x]_{补} [xy]=[zn]+(y1y0)[x]
这里的 z z z指的是从booth公式中最右端开始,每次加上它左边的项再乘1/2(右移一位)的临时的结果。
可将计算结果简化为如下表格

y i y_i yi y i + 1 y_{i+1} yi+1 y i + 1 − y i y_{i+1}-y_{i} yi+1yi操作
000右移一位
011 + [ x ] 补 , 右 移 一 位 +[x]_补,右移一位 +[x]
10-1 − [ x ] 补 , 右 移 一 位 -[x]_补,右移一位 [x]
110右移一位

这里特别需要注意的是无论是 + [ x ] 补 +[x]_补 +[x]或者是 − [ x ] 补 -[x]_补 [x]都是对于高n位进行操作的。

  • 21
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Alfred young

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

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

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

打赏作者

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

抵扣说明:

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

余额充值