有符號數處理

维基百科,自由的百科全书
跳转至: 导航搜索

计算机运算中,有符号数的表示需要将负数编码为二进制形式。

数学中,任意基数的负数都在最前面加上“−”符号来表示。然而在计算机硬件中,数字都以无符号的二进制形式表示,因此需要一种编码负号的方法。当前有四种方法,用于扩展二进制数字系统,来表示有符号数:原码(sign-and-magnitude),反码(ones' complement),补码(two's complement),以及移码excess-N

原码方法[编辑]

8位原码
二进制 有符号 无符号
00000000 +0 0
00000001 1 1
... ... ...
01111111 127 127
10000000 −0 128
10000001 −1 129
... ... ...
11111111 −127 255

为了解决表示一个数字的符号的问题,首先的处理办法应该是分配一个符号位来表示这个符号:设置这个(通常为最高有效位)为0表示一个正数,为1表示一个负数。数字中的其它位指示数值(或者绝对值)。因此一个字节只有7位(除去符号位),数值的范围从0000000(0)到1111111(127)。这样当你增加一个符号位(第八位)后,可以表示从−12710到+12710的数字。这种表示法导致的结果就是可以有两种方式表示0,00000000(0)与1,0000000(−0)。十进制数−43用原码方法编码成八位一字节的结果为10101011。

这种方法被直接比较于常用的符号表示法(放置一个“+”或者“−”在数字的数值之前)。一些早期的二进制电脑(例如IBM 7090)使用这种表示法,也许是由于它与通用用途的自然联系。原码是最常用的表示浮点值有效数字的方法。

反码[编辑]

8位反码
二进制值 反码表示 无符号数表示
00000000 +0 0
00000001 1 1
... ... ...
01111101 125 125
01111110 126 126
01111111 127 127
10000000 −127 128
10000001 −126 129
10000010 −125 130
... ... ...
11111110 −1 254
11111111 −0 255

另一方面,一种叫做反码的系统也可以用于表示负数(注:正数与原码形式一样,无需取反)。一个负二进制数的反码形式为在原数基础上按位取反,即对应正数的补。同原码表示一样,0的反码表示形式也有两种:00000000(+0)与11111111(−0)。

举例来说,原码10101011(-43)的反码形式为11010100(−43)。有符号数用反码表示的范围为−(2N−1−1)到(2N−1−1),以及+/−0。传统的表示为−12710到+12710,以及00000000(+0)或者11111111(−0)。

对两个反码表示形式的数字做加法,首先需要进行常规的二进制加法,但还需要在和的基础上加上进位。为什么必须这样呢?来看下面这个−1加上+2的例子。

           二进制    十进制
        11111110     -1
     +  00000010     +2
    ............    ...
      1 00000000      0   <-- 错误答案
               1     +1   <-- 加上进位
    ............    ...
        00000001      1   <-- 正确答案

在上面的例子中,二进制加法仅仅得到了00000000,这是一个错误的答案。只有当加上进位时才能得到正确答案(00000001)。

反码这种数字表示系统通常出现在老式的计算机中;PDP-1CDC 160AUNIVAC 1100/2200系列以及其它的一些电脑都使用反码算术。

关于正字法(orthography)的评述:这个系统之所以被称作反码(ones' complement)是因为一个正值x的反(表示为按位非x)也可以通过0的反码(ones' complement)表示形式(一长串的1,−0)减去x得到。

Internet协议IPv4ICMPUDP以及TCP都使用同样的16位反码检验和算法。虽然大多数计算机缺少“循环进位”硬件,但是这种额外的复杂性是可以接受的,因为“对于所有位(bit)位置上的错误都是同样敏感的”。[1]UDP中,全0表示省略了可选的检验和特性。另外一种表示:FFFF,指示了0的检验和。[2] (在IPv4中,TCP和ICMP都强制性地规定了检验和,而在IPv6中可以省略)。

注意负数的反码只需按位求数值的补就可以得到,符号不需要变动

补码[编辑]

8位补码
二进制值 补码表示 无符号数表示
00000000 0 0
00000001 1 1
... ... ...
01111110 126 126
01111111 127 127
10000000 −128 128
10000001 −127 129
10000010 −126 130
... ... ...
11111110 −2 254
11111111 −1 255

补码回避了0有多种表示的问题以及循环进位的需要。在补码表示中,负数以位模式表示为正值的反码加1(当作无符号数)。

在补码表示中,只有一个0(00000000)。求一个数的否(无论是负数还是正数)需要反转所有位,然后加1。一对补码整数相加等价于一对无符号数相加(除了溢出检测,如果能够做到的话)。比如,从旁边的表格可以看出,127与−128的补码表示相加就与无符号数127及128相加具有相同的结果。

得到一个数字补码的简单方法表示如下:

例1 例2
1. 从右边开始,找到第一个'1' 0101001 0101100
2. 反转从这个'1'之后开始到最左边的所有位 1010111 1010100

移码[编辑]

移码,是将二进制原码无符号整数所代表的值,减去一个预设值。

标准移码,预设值为二进制原码表示的最大整数的一半。 一个数的移码和补码,最高位相反,其余各位均相同。

引用[编辑]

  1. ^ Braden, R. Computing the Internet Checksum (RFC 1071). The Internet Engineering Task Force. 1988.九 [2009-06-11]. 
  2. ^ Postel, J. User Datagram Protocol (RFC 768). The Internet Engineering Task Force. 1980.八 [2009-06-11].