2.4 有符号整数
尽管负数可以用很多种不同的方式表示,但计算机设计者选择了3种方法:符号及值表示法,二进制补码表示法,移码表示法。每种方法都有其各自的优点和缺点。
2.4.1 符号及值表示法
一个n位字可以表示从0~2n-1共2n个可能的值。例如,用一个8位的字可以表示0,1,…,254,255。表示负数的一种方法是用它的最高位表示符号。通常符号位为0表示正数,符号位为1表示负数。
有符号数的值可被表示为(-1)S×M,这里S为数的符号位的值,M为其数值部分。若S=0,则(-1)0=+1,该数为正数。如果S=1,则(-1)1=-1,该数为负数。例如,下面两个8位有符号二进制数00001101和10001101的值为
n位有符号的表示范围为-(2n-1-1)至+(2n-1-1)。一个8位有符号数可以表示-127(11111111)至+127(01111111)之间的整数。有人反对该系统的一个原因是它有两个值都表示0:
00000000 = +0 以及 10000000 = -0
符号及值表示法并没有被用于整数算术运算中,因为它的加、减法运算分别用加法器和减法器实现。很快我们就会看到另外一些只需使用加法器的负数表示方法。符号及值表示法用于浮点算术运算中。
2.4.2 二进制补码运算
微处理器用二进制补码系统表示有符号整数,因为它可以将减法运算转换为对减数的补数的加法运算。用7加上5的补数就可以完成运算7减去5。
一个n位二进制数N的二进制补码定义为2n-N。如果N = 5 = 00000101(8位二进制数),则N的补码为28 - 00000101 = 100000000-00000101=11111011。注意,11111011也可以代表-00000101(-5)或+123,这取决于我们是将二进制数11111011看作补码还是非符号整数。
下面的例子说明了8位二进制数的补码运算过程。首先我们将4个数+5,-5,+7和-7转换为补码。
+5=00000101 –5=11111011 +7=00000111 –7=11111001
现在将7与5的互补数相加,
00000111 7
- 11111011 –5
100000010 2
结果为9位二进制数100000010。如果忽略最左边一位(也叫“进位位”),结果为000000102= +2,这正是我们所希望看到的结果。下面来看看–7加5,
00000101 5
- 11111001 –7
11111110 –2
结果为11111110(进位位为0)。我们预期的结果为-2;即28-2=10000000-00000010 =
11111110。我们再一次得到了所需要的结果。
二进制补码算术可不是魔术。请考虑n位二进制算术运算Z=X-Y,我们用X加上Y的补数来完成这一运算。Y的补码为2n-Y,则有Z=X+(2n-Y)=2n+(X+Y)。
换句话说,我们得到了所需要的结果,X-Y,以及位于最左边的一个并不需要的进位(即2n),而这个进位被丢弃了。
对一个数两次求补将得到这个数本身;例如,-5=28-00000101=11111011。再次求补,我们将得到:-(-5)=10000000-11111011=00000101=5。即-x=2n-x且-(-x)=2n-(2n-x)= x。请考虑下面的加法实例,它涵盖了被加数与加数分别为正和为负时全部四种可能的情形。
将结果视为补码时,所有4个例子都得到了我们所期望看到的结果。例3将6与9的补数相加完成运算-9+6,得到-3。-3的补码为10000000 - 00000011 = 11111101。
例4计算-X + -Y,得到-15,但这是一个模2n加法的结果。-15的补码为10000000 - 00001111 = 11110001。当两个数都是负数时,有(2n-X)+(2n-Y)=2n+(2n-X-Y)。这个表达式的第一部分是模2n加法时冗余的2n,第二部分为-X-Y的互补数。对于正数和负数加法的所有情形,补码都可以得到正确的结果。
1.求补运算
如果不是因为求补运算非常简单,补码不会有这样的吸引力。请考虑一个n位二进制补码数N,它被定义为2n-N。将表达式2n-N变为下面的形式:2n-1-N+1=111...1-N+1
例如,8位(n=8)时有
``28-N=100000000-N=100000000-1-N+1(调整后)
=11111111-N=1``
表达式11111111-N的值很容易计算。对于N的第i位,ni,若ni = 0,则1-0=1。同样,若ni=1,则1-1=0。显然1-ni=ni。可见计算N的补码非常容易,所要做的就是将N的每一位取反并将结果加1。例如,对于下面的5位二进制数有
-7=00111+1=11000+1=11001```
这种求补码的方法的优点在于它很适合用硬件实现。
2.补码的特点
1)补码是一个真正的互补系统,因为+X + (-X) = 0。
2)补码0被表示为00…0,是唯一的。
3)补码的最高位为符号位。如果符号位为0,则该数为正;符号位为1,则该数为负。
4)n位二进制补码数的表示范围为-2n-1~2n-1-1。对于n=8,补码表示范围为-128~127。共有28=256个不同的数(128个负数,1个0,127个正数)。
5)补码加法和减法使用同样的硬件完成,因为补码减法由被减数加上减数的补数实现。
3.运算溢出
n位二进制补码数的表示范围为-2n-1~2n-1-1。如果破坏了这个规则,即运算结果位于这个范围之外,会发生什么?5位有符号二进制补码数的表示范围为-16~+15。请考虑下面的例子,
![QQ_20170526171913](https://yqfile.alicdn.com/2412e4dcda29c3ef6fad6b894d1847d82ef0d470.png)
情形1中,我们得到了期望的结果+1210,但情形2中,我们得到的结果为负数,因为它的符号位为1。如果将结果视作无符号数,它将是+25,这个值显然是正确的。然而,既然我们已经选择补码作为负数的表示方法,所有运算结果都必须有一个合理的解释。
同样,如果两个负数相加且结果小于-16,也会超出5位二进制补码的表示范围。例如,将-9=101112与-12=101002相加,得到
![QQ_20170526171932](https://yqfile.alicdn.com/eb6d23b96e27ce880b8aba70ee7b0691ddfe0acd.png)
这两个例子都说明了什么是运算溢出,它发生在补码加法当两个正数的和为负数,或两个负数的和为正数的时候。如果操作数A和B的符号位相同但结果的符号位与它们不同,则发生了溢出。假设A的符号位为an-1,B的符号位为bn-1,A与B之和的符号位为sn-1,则可以用下面的逻辑表达式判断是否溢出(下节将介绍逻辑表达式)。
![QQ_20170526171956](https://yqfile.alicdn.com/2f45944b61d41406b91111eac3e96c023707756e.png)
实践中,真实系统通过加法器的进位输入和输出的最高位来判断是否发生溢出,即V=Cin ≠ Cout。溢出是补码运算的结果,不应与进位混淆,是否产生进位由被加数与加数的最高两位之和决定。