前言:
补码的理解:
1)思路1:将负数变成正数,如钟表,当前时间-1,与+11相同。 补码= 该负数+模
11= -1+12,12为模
原理:11和-1是相较12的同余数。,这样实现了用一个正数替换一个负数。
参考该文。
2)思路2:周期函数的角度来理解,周期函数的性质,f(x)=f(x+T),T为周期。
上例中钟表的例子,12即为周期,当前时间-1 =当前时间-1+12=当前时间+11.
以下示例来源于原码,反码,补码杂谈 - 方戈 - 博客园
- 计算机中存的是补码。
- 正数的补码等于其本身;
- 负数补码的计算方法:负数的补码等于负数加上模(负加模-----因为负数的绝对值与其补码之和等于模);实质是同余数(时钟原理);
- 对于一个4位的二进制数来说,我们用首位为1的8个数,来表示负数,首位为0的8个数来表示非负数;
- 4位的二进制数,共能表示2*2*2*2=16个数,故其模为16.
比如:4位运算,,-1的补码是-1+16 = 15;(1111),这种理解方式,其实是没有符号位的概念。。。即:我们用同余数来表示这个负数。
4位运算,我们只使用了3位,将高位作为符号位,因此我们将高位是1的8个数,用来表示负数。
- 之所以-1的补码是1111,-2的补码是1110,是因为 -2 + 1 = -1 (即:1110 +0001 = 1111);
而 0 = -1 + 1;即:(1111 + 0001 = 0000),所以,-0(补码0000 )和+0(0000)合二为0;这样多出来一个编码:1000,他没有原码(没有哪个原码的补码是1000),因为 1000+1 = 1001(-7),所以我们将1000代表为-8的编码;因此,-8是没有原码的(因为1000是没有原码的。)
(六)补码实例
好吧,接下来我们就做一做四位二进制数的减法吧(先不引入符号位)
0110(6)-0010(2)【6-2=4,但是由于计算机中没有减法器,我们没法算】
这个时候,我们想想时钟运算中,减去一个数,是可以等同于加上另外一个正数(同余数)
那么这个数是什么呢?从时钟运算中我们可以看出这个数与减数相加正好等于模。
那么四位二进制数的模是多少呢?也就是说四位二进制数最大容量是多少?其实就是2^4=16=10000B
那么2的同余数,就等于10000-0010=1110(14)
既然如此
0110(6)-0010(2)=0110(6)+1110(14)=10100(20=16+4)
OK,我们看到按照这种算法得出的结果是10100
,但是对于四位二进制数,最大只能存放4位(硬件决定了),如果我们低四位,正好是0100(4)
,正好是我们想要的结果,至于最高位的‘1’
,计算机会把他放入psw寄存器进位位中。
8位机则会放在cy
中,x86会放在cf
中(这个我们不作讨论)
这个时候,我们再想想在四位二进制数中,减去2,就相当于加上它的同余数14(至于它们为什么同余,还是建议看《计算机组成原理》)
但是减去
2
,从另外一个角度来说,也是加上(-2)
。即加上(-2)
和加上14
其实得到的二进制结果除了进位位,结果是一样的。如果我们把
1110(14)
的最高位看作符号位后就是(-2)
的补码,这可能也是为什么负数的符号位是‘1’
而不是‘0’
,
而且在有符号位的四位二进制数中,能表示的只有‘-8~7’
,而无符号位数(14)
的作用和有符号数(-2)
的作用效果其实是一样的。
那正数的补码呢?加上一个正数,加法器就直接可以实现。所以它的补码就还是它本身。
下图给出带符号位四位二进制的补码表示法
由上图可以看出来,1000是没有原码的,因为1001(-7)+1111(-1) = 1000(-8);所以,我们规定1000为-8.
到这里,我们发现原码,反码的问题,补码基本解决了。
在补码中也不存在负零了,
因为1000表示-8
这是因为根据上面的补码图,做减法时,0001(1)+1111(-1)=0000
我们再也不需要一个1000
来表示负0
了,就把它规定为-8
负数与负数相加的问题也解决了1111(-1)+1110(-2)=1101(-3)
可能说得有点绕,但是实在是没办法。其实我觉得补码还可以这样画。
很优美有没有,如果你想想地理课本,0不就相当于本初子午线,-8不就是180°,而正数相当于西经,负数相当于东经。
(七)为何这样求补码
然后我们再来看看为什么负数的补码的求法为什么是反码+1
因为负数的反码加上这个负数的绝对值正好等于1111,再加1,就是1000,也就是四位二进数的模
而负数的补码是它的绝对值的同余数,可以通过模减去负数的绝对值,得到他的补码。
所以 负数的补码就是它的反码+1。
有点绕吧,只能说很难算清楚,你们还是自己算算吧。还有上面我提到的另外一种算法。
接下来,我要说一下我自己算补码的小技巧。
看上面那个图。
如果我们把-8当成负数的原点。那么-5的补码是多少呢?
-5=-8+3
-5的补码就是-8的补码加3
1000(-8) +0011(3)=1011(-5)
所以完全可以口算出-5的补码是1011
当然,也可以记住-1的补码是1111
口算减法得出(计算机没法算减法,我们可以人为的算减法,就像算十进制减法一样。)
对于八位加法器的话,可以把-128
当补码原点。十六位可以把-32768
当补码原点。
是的,128
是256
(八位二进制数的模)的一半,32768
是65536
(十六位二进数的模)的一半
也很方便有没有,而且简单的是
补码原点总是最高位是
‘1’
,其他位是‘0’
所以做加法总是简单得可以口算。
总结:
综上,求补码的两种方式:
1)通过负加模思路
如单字节中,-128的补码是-128+256 = 128(0x80);-1的补码是-1+256=255(0xFF).
2)通过最小的负数来求补码
如单字节,-120的补码是 -120 = -128+8 = 0x80+0x08=0x88