补码乘法
(写的很乱,很杂,反正也没有人看 :>,就不讲究了)
起因
昨天嵌入式系统课上,老师专门讲了,补码的一系列运算.可是我没有听懂补码乘法相关的内容(补偿法?),所以自己再推一下.
前提
- 在不溢出的前提下,补码所表示的数可以进行正确的左移运算,并且,左移等价于乘2
- 补码的加法可以通过溢出保证结果的正确性,(无论对于有符号数还是无符号数)
- 由(1)(2)知当第二个乘数为正时,无论第一个乘数的正负号,都可以保证结果的正确性(不溢出的情况下),因为运算相当于左移和加的结合.
当第二个乘数为负数时
这里以8位二进制数乘8位二进制数,并且用16个二进制位来保存结果为例.
使用
A
A
A,
B
B
B分别表示第一个和第二个乘数的绝对值,数值直接写作补码的形式,或称为unsigned 的形式(当作unsigned 时计算也是正确的).
- 如果我们只是直接按照unsigned 进行乘.
A × ( 2 8 − B ) = 扩展成16位 A × ( 2 16 − B ) = A × ( 2 16 − B ) m o d 2 16 = A × 2 16 m o d 2 16 − A × B m o d 2 16 = 0 − A × B m o d 2 16 = 2 16 − A × B A \times (2^8-B)\xlongequal{\text{扩展成16位}}A\times (2^{16}-B)\\ =A\times (2^{16}-B)\mod 2^{16}\\ =A\times 2^{16}\mod 2^{16}-A\times B\mod 2^{16}\\ =0-A\times B \mod 2^{16}\\ =2^{16}-A\times B A×(28−B)扩展成16位A×(216−B)=A×(216−B)mod216=A×216mod216−A×Bmod216=0−A×Bmod216=216−A×B
那么我们会得到正确的结果,但是显然前面补充的符号位是没有必要的. - 我们以可以对 A A A, B B B进行求补,即 A × ( 2 8 − B ) = ( 2 8 − A ) × B A\times (2^8-B)=(2^8-A)\times B A×(28−B)=(28−A)×B
- 补码校正法,只应用了一次取补,结论是:
[ A × B ] 补 = A 补 × ( 0 b n − 2 b n − 3 ⋯ b 2 b 1 b 0 ) + [ − A ] 补 × 2 n − 1 × b n − 1 [A\times B]_补=A_补\times (0b_{n-2}b_{n-3}\cdots b_2b_1b_0)+[-A]_补\times 2^{n-1}\times b_{n-1} [A×B]补=A补×(0bn−2bn−3⋯b2b1b0)+[−A]补×2n−1×bn−1
推导:
A × ( 2 8 − B ) = d i s c a r d m s b 扩 展 到 16 位 ( A × ( 2 7 − B ) + C ( 补 偿 ) ) m o d 2 16 = ( A × 2 7 − A B + C ) m o d 2 16 A \times (2^8-B)\xlongequal[discard\ msb]{扩展到16位}(A\times (2^{7}-B)+C(补偿))\mod 2^{16}\\ =(A\times 2^7-AB+C)\mod 2^{16} A×(28−B)扩展到16位discard msb(A×(27−B)+C(补偿))mod216=(A×27−AB+C)mod216
在 m o d 2 16 \mod 2^{16} mod216的意义下,取 C = 2 16 − A × 2 7 C=2^{16}-A\times 2^7 C=216−A×27即是 − A -A −A的16位补码.
总结
在乘的时候只要保证unsigned的值合法,负数的值就是合法的,原理是同余定理,无论是unsigned还是负数在 m o d 2 16 \mod 2^{16} mod216的意义下都是相同的.