一眼看懂二进制补码的计算方法
最近,我仔细研究了下linux下,C程序的编译和链接过程。反汇编和查看二进制时,难免看到大量整数的二进制表示,特别是负数,例如0xfffffffc,这个是多少?记得有个转换方法,首先这个数是一个负数,它的绝对值是 ~(0xfffffffc)+ 1 = 0x00000003 + 1 = 4
, 所以值为-4
。
那么这个取反加一
的方法是怎么得来的呢?我想不起来了。就自己鼓捣了一下:
我们考虑两个8bit寄存器A,B相加:
比如 A=128, B=132, 我们把计算机计算结果用[]括起来:
[A + B] = [0x80 + 0x84] = [1000 0000 + 1000 0100] = (1 0000 0100) 8bits截断 = 0000 0100 = 4
= A + B - 256 = A + B - 2^8
其实对于任何nbits寄存器,[An + Bn + 2^n]= ( An + Bn - 2^n ) + 2 ^n = An + Bn
即:[An + Bn + 2^n] = An + Bn
。
我们知道在二进制电路中,减法实际上也是通过加法来实现的。
因为 ,由于这里还没有引入负数的表示,先假设An > Cn, 则[An + (2^n - Cn )]= (An - Cn) + 2^n = An - Cn
也就是 ,如果我们要计算 An - Cn
其实,计算机可以直接用An
加上2^n - Cn( > 0)
来计算。
所以我们就把 2^n - Cn
叫做-Cn的补码,对应的二进制值就是-Cn的二进制表示, 为了不和正整数冲突,考虑到最高位对负数来说始终为1, 就称为了符号位,对应的正整数也只能使用余下的n-1位来表示。
对了刚才我们是假设An > Cn
,现在我们来看看,如果把2^n - Cn
对应的二进制定义为-Cn
的二进制格式。
那么,当 An < Cn
时,[An + (2^n - Cn )]
是否也对应着An - Cn
的二进制格式呢?
这个是显然的。因为 An + (2^n - Cn ) = 2^n - (Cn - An)
也就是 - (Cn - An)的二进制表示。
既然体会到了 2^n - Cn就是-Cn的补码,那么补码的计算很容易得出:
2^n = 2^n-1 + 2^n-2 ... + 2^2 + 2^1 + 1 + 1
Cn = bit(n-1)*2^n-1 + bit(n-2)* 2^n-1 ...+ bit(3)* 2^2 + bit(1)*2^1 + bit(0)*1.
2^n-Cn = ~bit(n-1)*2^n-1 + ~bit(n-2)* 2^n-1 ...+ ~bit(3)* 2^2 + ~bit(1)*2^1 + ~bit(0)*1 + 1.
= ~Cn + 1
就是
-Cn的补码 = 2^n - Cn = = ~Cn + 1
看来很容易懂啊。