补码乘法运算的原理
补码的出现统一了计算机运算中的加减法操作,那对于补码的乘法该如何操作呢?
补码表示法
- 纯小数补码的定义
[
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>x≥00>x≥−1(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>x≥00>x≥−2n(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.x1x2…xn[y]补=y0.y1y2…yn
其中
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
[x∗y]补=x补∗(0.y1y2…yn)−[x]补∗y0
下来证明这一结论:
- 首先考虑乘数
y
y
y为正数的情形
- 假定被乘数
x
x
x也为正数,则此时是两个正数相乘。
对于正数,它的原码,补码,反码是相同的,所以根据原码乘法的正确性可以得到这种情形也是正确的。
- 假定被乘数
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.x1x2…xn=2+x=2n+1+x[y]补=y0.y1y2…yn=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+1∗y+x∗y
其中
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.y1y2…yn=i=1∑nyi∗2−i
所以
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+1∗y=2i=1∑nyi∗2n−i
式中的 n − i > = 0 n-i>=0 n−i>=0因此
∑ i = 1 n y i ∗ 2 n − i \sum_{i=1}^{n}y_i*2^{n-i} i=1∑nyi∗2n−i是一个整数。
所以
2 n + 1 ∗ y 2^{n+1}*y 2n+1∗y是一个偶数。
所以
[ 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+1∗y+x∗y=2+xy=[x∗y]补
这一步是根据x*y是负数所以有 2 + x y = [ x ∗ y ] 补 2+xy=[x*y]_补 2+xy=[x∗y]补
- 假定被乘数
x
x
x也为正数,则此时是两个正数相乘。
- 接着考虑乘数
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.y1y2…yn=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.y1y2…yn−2=0.y1y2…yn−1
此时我们发现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]_补 [x∗y]补=[x∗(0.y1y2…yn)]补+[−x]补=[x]补∗(0.y1y2…yn)+[−x]补
结合第一种情形
[ x ∗ y ] 补 = [ x ] 补 ∗ ( 0. y 1 y 2 … y n ) [x*y]_{补}=[x]_补*(0.y_1y_2\dots y_n) [x∗y]补=[x]补∗(0.y1y2…yn)
将两种情况统一,可得到:
[ 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 [x∗y]补=[x]补∗(0.y1y2…yn)−[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
[x∗y]补=[x]补(0.y1y2…yn)−[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}
[x∗y]补=[x]补(0.y1y2…yn)−[x]补∗y0=[x]补∗(−y0+y12−1+y22−2+…yn∗2−n)=[x]补∗[−y0+(y1−y1∗2−1)+(y2∗2−1−y2∗2−2)…]=[x]补∗[(y1−y0)+(y2−y1)∗2−1…(yn−yn−1)∗2−(n−1)+(0−yn)∗2−n]
所以我们根据上式可以得到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=2−1{(yn+1−yn)[x]C+[z0]C}⋮[zn]C=2−1{(y2−y1)[x]C+[zn−1]C}
故最终的结果为:
[
x
∗
y
]
补
=
[
z
n
]
补
+
(
y
1
−
y
0
)
[
x
]
补
[x*y]_{补}=[z_n]_{补}+(y_1-y_0)[x]_{补}
[x∗y]补=[zn]补+(y1−y0)[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+1−yi | 操作 |
---|---|---|---|
0 | 0 | 0 | 右移一位 |
0 | 1 | 1 | + [ x ] 补 , 右 移 一 位 +[x]_补,右移一位 +[x]补,右移一位 |
1 | 0 | -1 | − [ x ] 补 , 右 移 一 位 -[x]_补,右移一位 −[x]补,右移一位 |
1 | 1 | 0 | 右移一位 |
这里特别需要注意的是无论是 + [ x ] 补 +[x]_补 +[x]补或者是 − [ x ] 补 -[x]_补 −[x]补都是对于高n位进行操作的。