补码是计算机语言中很基础也很重要的一个概念,教科书上讲,计算机中的数值都是以补码的形式存储的,有了补码,可以变减法为加法,但具体怎么实现的呢?先从基础说起。
无符号整数
此类型表示范围是正整数和0,不含负数。如8位无符号数的表示范围为:0~255.无符号数的每一位都有权重。
有符号整数
表示范围基本上是一半正整数,一半负整数。8位有符号整数的大致范围为-127~127.有符号整数的最高位用来表示数的正负,一般用0表示正数,用1表示负数,该位被称为符号位,没有权重。
无符号整数和有符号整数在形态上并没有区别,以8位整数10000010B(B表示2进制数)为例。它可以作为无符号数来使用,其最高有效位上的“1”表示它对该数的值的贡献为2的7次幂,即128,它对应的真值为130;该8位整数也可以作为有符号数来使用,其最高有效位上的“1”表示它是一个负数,但到底其值是多少,有待继续讨论。
下表为8位整数的原码、反码、补码表示形式
十进制数 | 二进制真值 | 原码表示 | 反码表示 | 补码表示 |
---|---|---|---|---|
+127 | +1111111 | 01111111 | 01111111 | 01111111 |
+126 | +1111110 | 01111110 | 01111110 | 01111110 |
+2 | +0000010 | 00000010 | 00000010 | 00000010 |
+1 | +0000001 | 00000001 | 00000001 | 00000001 |
+0 | +0000000 | 00000000 | 00000000 | 00000000 |
-0 | -0000000 | 10000000 | 11111111 | 00000000 |
-1 | -00000001 | 10000001 | 11111110 | 11111111 |
-2 | -00000010 | 10000010 | 11111101 | 11111110 |
-126 | -1111110 | 11111110 | 10000001 | 10000010 |
-127 | -1111111 | 11111111 | 10000000 | 10000001 |
-128 | -10000000 | 不能表示 | 不能表示 | 10000000 |
原码表示法
符号位为0表示正,为1表示负;其余各位等同于真值的绝对值。8位原码的表示范围为:-127~+127。
反码表示法
符号位为0表示正,为1表示负;正数的表示同原码,负数的表示是在原码表示的基础上通过将符号位以外各位取反来获得。8位反码的表示范围为-127~+127。
补码表示法
符号位为0表示正,为1表示负;正数的表示同原码,负数的表示是在反码表示的基础上通过加1来获得。由于数据0的表示方法唯一,并被划归为正数,所以负数方向的表示能力比正数多出一个,这个多出的负数为-128。8位补码的表示范围为-128~+127。采用补码,可以将两个数的减运算变为这两个数补码的加运算来实现。对计算机来说,求补和求和都是很简单的运算,比减法容易实现。
求补运算
将一个负数由真值变为补码或者反向变化,或者将连个数的减法变为补码相加,都会用到求补运算。除了“求反加1”的方法外,还可以采用“带借位0减”的方法。
例如,将真值-37H(H表示16进制数,即-00110111B)变为它对应的8位补码:
1,00000000B - 00110111B = 11001001B = C9H
又如,将8位补码B8H(即10111000B,注意它是一个负数)还原为真值:
-[1,00000000 - 10111000B] = -01001000B = -48H
采用“带借位0减”的方法,对十六进制数的求补运算尤其方便,例如对-37H求补:
1,00H - 37H = C9H
减法运算
8位整数的减法运算,在计算机中通过补码加来实现,例如:
X - 37H = X + C9H