补码的表示
教科书上一般是通过原码引出补码的,这样会导致对最高位的意义理解不够透彻,这里介绍一种csapp上给出补码的方式。
X=Σpi*wi
这里的wi是第i位所代表的权值,pi是第i位的取值,为0或者1
n=8的补码表示如图所示
从图中很容易看出,补码中只有一个0,即00000000
补码的加减法
[x]表示x的补。
补码的加法
[x+y]=[x]+[y]。
分几种情况考虑
x与y都是正数
x+y<=127
1+1=2:
-128 64 32 16 8 4 2 1
0 0 0 0 0 0 0 1
+0 0 0 0 0 0 0 1
=0 0 0 0 0 0 1 0
x+y>127
64+64=128:
-128 64 32 16 8 4 2 1
0 1 0 0 0 0 0 0
+0 1 0 0 0 0 0 0
=1 0 0 0 0 0 0 0
此时所得结果为-128,实际上是真实值128-256所得,为什么这样呢?
考虑图上权值,两个正数64相加,本来应该进位到128,但是却进位到了-128,所以与真实值相差256。
x与y都是负数
-128<=x+y<0
-63+(-35)=-98:
-128 64 32 16 8 4 2 1
1 1 0 0 0 0 0 1
+ 1 1 0 1 1 1 0 1
=(1)1 0 0 1 1 1 1 0
这里其实很有意思,为什么溢出之后舍去了一位反而计算的结果是正确的呢。
实际上,-63=-128(最高位)+65(后面7位),-35=-128(最高位)+93(后面7位),
-63+(-35)=(-128+-128)+(65+93)=(-256)(溢出到下一位)+(158)=158
而根据我们之前加法溢出的结论,158=158-256=-98。
接下来我把上面的分析通用化。
因为-128<=x+y<0,也就意味着128<=x+y+256(考虑之前分析中分离两个-128的过程,实际上相当于加256)<256。
所以每一个该范围内的x+y都可以利用上面的分析说明
即使产生了符号位的进位也能够得到正确的结果。
x+y<-128
-64+(-65)=-129:
-128 64 32 16 8 4 2 1
1 1 0 0 0 0 0 0
+ 1 0 1 1 1 1 1 1
=(1)0 1 1 1 1 1 1 1
显然,得到的结果为127=-129+256.
按照上面的分析模式,两个负数相加必然会丢失一个-256,也就相当于结果加上256.
于是x+y<-128,x+y+256<128,根据上面对于正数的分析,不会产生正数溢出,因此得到一个正数的结果。
X为正,y为负(正数加负数)
63+(-35)=28:
-128 64 32 16 8 4 2 1
0 0 1 1 1 1 1 1
+ 1 1 0 1 1 1 0 1
=(1)0 0 0 1 1 1 0 0
依然考虑63+(-128+93)=-128+(63+93)=-128+156=28
也就是说,将负数y化为y=-128+y',y'为正数
如果x+y'>=128,那么显然会溢出一位到-128,正好与y本身的-128抵消,最终答案为x+y'-128=x+y
如果x+y'<128,则不会溢出,最后答案为x+y'-128=x+y
第二种情况的-128是因为没有抵消掉的那个y自带的-128,第一种情况的-128是因为相加的结果溢出了128。
补码的减法
[x-y]=[x]+[[y]]
可以转化为加法的情况
不再讨论。