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