在计算机运算时，需要将负数编码至二进制形式,其所用的编码方法称为**有符号数的表示**。

在数学中，可以在任意基数的数前面添加负号"−"来表示负数。然而在随机存取存储器和寄存器中，数据均以一系列二进制位表示而没有额外的标志，因此需要一种编码负号的方法。当前有四种方法，用于扩展二进制数字系统，来表示有符号数：**原码**（）、**反码**（）、**补码**（）以及**移码**（，）。

原码
--


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

条目：原码
符號及值（sign & magnitude）的处理办法是分配一个符号位（sign bit）来表示这个符号：设置这个位（通常为最高有效位）为*0*表示一个正数，为*1*表示一个负数。数字中的其它位指示数值（或者绝对值）。因此一个字节只有7位（除去符号位），数值的范围从0000000（0）到1111111（127）。这样当你增加一个符号位（第八位）后，可以表示从−12710到+12710的数字。这种表示法导致的结果就是可以有两种方式表示零，00000000（0）与10000000（−0），這大大增加數碼電路的複雜性和設計難度。CPU亦須執行兩次比較，來測試運算結果是否為零。

十进制数−43用原码方法编码成八位的结果为10101011。

这种方法被直接比较于常用的符号表示法（放置一个"+"或者"−"在数字的数值之前）。一些早期的二进制电脑（例如IBM 7090）使用这种表示法，也许是由于它与通用用途的自然联系。原码是最常用的表示浮點數的方法。IEEE二進位浮點數算術標準（IEEE 754）採用最高有效位作為符号位，因此可表示正負零及正負無限。

反码
--

条目：和反码

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-1，CDC 160A，UNIVAC 1100/2200系列以及其它的一些电脑都使用反码算术。

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

Internet协议IPv4，ICMP，UDP以及TCP都使用同样的16位反码检验和算法。虽然大多数计算机缺少"循环进位"硬件，但是这种额外的复杂性是可以接受的，因为"对于所有位（bit）位置上的错误都是同样敏感的"。 在UDP中，全0表示省略了可选的检验和特性。另外一种表示：FFFF，指示了0的检验和。 （在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' | 010100**1** | 0101**1**00 |
| 2. 反转从这个'1'之后开始到最左边的所有位 | **101011**1 | **1010**100 |

移码
--

条目：移码
移码（），是将二进制原码无符号整数所代表的值，减去一个预设值。

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

表示方式
----

下表列出了 4-bit 二進數所能表示的整數：

* 無符號（unsigned）可表示0到15
* 符號及值（sign & magnitude）可表示-7到+7，包括-0
* 一補碼（ones' complement）可表示-7到+7，包括-0
* 二補碼（two's complement）可表示-8到+7，沒有±0的問題

| 二進數 | 無符號 | 符號位元 | 一補碼 | 二補碼 |
| --- | --- | --- | --- | --- |
| 0000 | 0 | 0 | 0 | 0 |
| 0001 | 1 | 1 | 1 | 1 |
| 0010 | 2 | 2 | 2 | 2 |
| 0011 | 3 | 3 | 3 | 3 |
| 0100 | 4 | 4 | 4 | 4 |
| 0101 | 5 | 5 | 5 | 5 |
| 0110 | 6 | 6 | 6 | 6 |
| 0111 | 7 | 7 | 7 | 7 |
| 1000 | 8 | -0 | -7 | -8 |
| 1001 | 9 | -1 | -6 | -7 |
| 1010 | 10 | -2 | -5 | -6 |
| 1011 | 11 | -3 | -4 | -5 |
| 1100 | 12 | -4 | -3 | -4 |
| 1101 | 13 | -5 | -2 | -3 |
| 1110 | 14 | -6 | -1 | -2 |
| 1111 | 15 | -7 | -0 | -1 |

参见
--

* 二進碼十進數
* 符号性
* 平衡三进制

参考资料
----

1. ↑  Braden, R.. The Internet Engineering Task Force. 1988  [2009-06-11]. （原始内容存档于2020-10-21）.
2. ↑  Postel, J.. The Internet Engineering Task Force. 1980  [2009-06-11]. （原始内容存档于2012-07-22）.