补码

**二補數**（英語：**2's complement**）是一種用二進位表示有符號數的方法，也是一種將數字的正負號變號的方式，常在電腦科學中使用。二補數以有符號位元的二進位數定義。

正數和 0 的二補數就是該數字本身再補上最高位元 0。負數的二補數則是將其絕對值按位元取反再加 1。

二補數系統的最大優點是可以在加法或減法處理中，不需因為數字的正負而使用不同的計算方式。只要一種加法電路就可以處理各種有號數加法，而且減法可以用一個數加上另一個數的二補數來表示，因此只要有加法電路及二補數電路即可完成各種有號數加法及減法，在電路設計上相當方便。

另外，二補數系統的 0 就只有一個表示方式，這和一補數系統不同（在一補數系統中，0 有二種表示方式），因此在判斷數字是否為 0 時，只要比較一次即可。

右側的表是一些 8-bit 二補數系統的整數。它的可表示的範圍包括 - 128 到 127，總共 256（=28）個整數。

## 數字表示方式

### 說明

以下用 4 位元的二補數數字來說明二補數系統的數字表示方式。

* 在表示正數和零時，二補數數字和一般二進位一樣，唯一的不同是在二補數系統中，正數的最高位元恆為 0，因此 4 位元的二補數正數，最大數字為 0111 (7)。
* 二補數數字的負數，最高位元恆為 1，4 位元二補數的數字中，最接近 0 的負數為 1111 (-1)，以此類推，因此絕對值最大的負數是 1000 (-8)。

以上的表示方式在電腦處理時格外方便，用以下的例子說明：

```
    0011 (3)
  + 1111 (-1)
--------------
   10010 (2)
```

結果 10010 似乎是錯的，因為已經超過四個位元，不過若忽略掉（從右開始數）第 5 個位元，結果是 0010 (2)，和我們計算的結果一樣。而且若可以將二進位的 1111 (-1) 變號為 0001 (1)，以上的式子也可以計算減法：3-1 = 2。

在 n 位元的二補數加減法中，忽略第 n+1 個位元的作法在各種有號數加法下都適用（不過在判斷是否溢位（overflow）時，仍然會用到第 n+1 個位元）。因此在二補數的系統，加法電路就可以處理有負數的加法，不需另外處理減法的電路。而且，只要有電路負責數字的變號（例如將 1 變換為 -1），也可以用加法電路來處理減法。而數字的變號就用計算數字的二補數來完成。

在一般 n 位元的二進位數字中，最高有效位元（MSB）第 n 位元代表的數字為　2n−1。不過，在 n 位元的二補數系統中，最高有效位元（MSB）第 n 位元表示符號位元，若符號位元為 0，數字為正數或 0，若符號位元為 1，數字為負數。以下是 n 位元的二補數系統中，幾個特別的數字：

因此，在 8 位元的二補數系統中，可以表示的最大正數為 28−1-1 = 127，可以表示最小的負數為 -28−1 = -128　

### 計算二補數

在計算二進制數字的二補數時，會將數字進行位元反相運算，再將結果加 1，不考慮溢位位元（一般情形，溢位位元會為 0），就可以得到該數字的二補數。

以下考慮用有符號位 8 位元二進位表示的數字 5：

　
: 0000 0101 (5)

其最高位元為 0，因為此數字為正數。若要用二補數系統表示 -5，首先要將 5 的二進位進行反相運算〔1 變為 0，0 變為 1
〕：

　
: 1111 1010

目前的數字是數字 5 的一補數，因此需要再加 1，才是二補數：

　
: 1111 1011 (-5)

以上就是在二補數系統中 -5 的表示方式。其最高位元為 1，因為此數字確實為負數。

一個負數的二補數就是其對應的正數。以 -5 為例，先求數字的一補數：

　
: 0000 0100

再加一就是 -5 的二補數，也就是 5。

　
: 0000 0101 (5)

簡單來說，數字 a（正負數皆可）的二補數即為 -a。

若要計算 n 位數二補數二進位對應的十進位，需要知道每位數對應的數字，除了最高位元外，其他位元的對應數字均和一般二進位相同，即第 i 位數表示數字 2i−1。但最高位元若為 1 時，其表示數字為 -2n−1，因此若用此方式計算 0000 0101 表示的數字，其結果為：

　
: 1111 1011 (−5) = −128 + 64 + 32 + 16 + 8 + 0 + 2 + 1 = (−27 + 26 + ...) = −5

### 特別的數字

有兩個數字的二補數等於本身：一個是 0，另一個為該位元內可表示有符號位區分的二進位形式的最大負數（即 1000...）。

0 的二補數計算方式（以 8 位元為例）如下：先計算它的一補數：

　
: 1111 1111

再將一補數加一：

　
: 0000 0000，溢位位元二進位值 = 1（二進位）

忽略溢位，其結果為 0（0 是唯一計算二補數過程中會出現溢位的數字。）。因此 0 的二補數為 0。而 0 x (-1) = 0，因此其二補數仍滿足「數字 a 的二補數為 -a」的原則。

若計算 1000 0000（這是 8 位元內可表示有符號位區分的二進位形式的最大負數**-128**）的二補數：先計算它的一補數：

　
: 0111 1111

再加一就是它的二補數。

　
: 1000 0000

1000 0000 (-128) 的二補數仍為 1000 0000 (-128)。但 (-128) x (-1) = 128，因此其二補數是以上規則的例外。

**總結**：由於 0 可以等於 0 的二補數**-0**，以及同樣因為 8 位元的二補數可顯示的值範圍為 -128 ~ 127，但 - 128 的二補數 **128** 無法用在已有位元數量為 8 的位元數量內的可用二補數表示。【在計算其他位數內的可表示有符號位區分的二進位形式的最大負數（即 1000...000）時，也會有類似情形。】

**所以**：**0** 和**-128** 的確是「數字 a 的二補數為 -a」原則中**兩個特別的數字**。

### 其他計算方法

#### 方法一

另一種計算 $-N$ 的二補數 $N^{*}$ 的公式如下：

　
: $N^{*}=2^{n}-N$

其中 $n$ 是整數的長度。

以八位元的「-123」（-11110112）求其二補數為例：

　
: $n=8$

　
: $N=+123=0111\ 1011_{(2)}$

-123 的二補數計算方式如下：

　
: $N^{*}=2^{n}-N={2^{8}}-0111\ 1011_{(2)}=1\ 0000\ 0000_{(2)}-0111\ 1011_{(2)}=1000\ 0101_{(2)}$

　
: $-123_{(10)}=1000\ 0101_{(2)}$

**驗證**
: $-123=-128+5=1000\ 0000_{(2)}+101_{(2)}=1000\ 0101_{(2)}$

#### 方法二

以另一種較簡單的方式，可以找出二進位數字的二補數：

* 先由最低位元開始找。
* 若該位元為 0，將二補數對應位元填 0，繼續找下一位元（較高的位元）。
* 若找到第一個為 1 的位元，將二補數對應位元填 1。
* 將其餘未轉換的位元進行位元反相，將結果填入對應的二補數。

以 0011 1100 為例（圖中的 ^ 表示目前轉換的數字，- 表示還不確定的位數）：

```
  原數字       二補數
0011 1100  ---- ---0（此位元為0） 
        ^

0011 1100  ---- --00（此位元為0） 
       ^

0011 1100  ---- -100（找到第1個為1的位元） 
      ^

0011 1100  1100 0100（其餘位元直接反相） 
^
```

因此其結果為 1100 0100

### 符號延展

將一個特定位元二補數系統的數字要以較多位元表示時（例如，將一個位元組的變數複製到另一個二個位元組），所有增加的高位元都要填入原數字的符號位元。在一些微處理機中，有指令可以執行上述的動作。若是沒有，需要自行在程式中處理。==>

在二補數系統中，當數字要向右位移幾個位元時，在位移後需將符號位元再填入原位置（算術移位），保持符號位元不變。以下是二個例子：

```
    數字      0010 1010             1010 1010
向右位移一次  0001 0101             1101 0101
向右位移二次  0000 1010             1110 1010
```

而當一個數字要向左位移 n 個位元時，最低位元填 n 個 0，權值最高的 n 個位被拋棄。以下是二個例子：

```
    數字      0010 1010             1010 1010
向左位移一次  0101 0100             0101 0100
向左位移二次  1010 1000             1010 1000
```

向右位移一次相當於除以 2，利用算術移位的方式可以確保位移後的數字正負號和原數字相同，因為一數字除以 2 後，不會改變其正負號。**注意**：向左位移一次相當於乘以 2，雖然乘以在理論上並不會改變一個數的符號，但是在二補數系統中，用以表示數的二進位碼長度有限，能夠表示的數的範圍也是有限的：若一個數的高權值上的數位已經被占用，此時再將這個數左移若干位（乘以 2n）的話，有可能造成數位溢位（overflow），高權值上的數將會失去，對於絕對值很大數，這將造成整體表達的錯誤。

## 二補數的工作原理

為什麼二補數能這麼巧妙實現了正負數的加減運算？答案是：指定 n 位元字長，那麼就只有 2n 個可能的值，加減法運算都存在上溢位與下溢位的情況，實際上都等價於模 2n 的加減法運算。這對於 n 位元無符號整數類型或是 n 位元有符號整數類型都同樣適用。

例如，8 位元無符號整數的值的範圍是 0 到 255. 因此 4+254 將上溢位，結果是 2，即 $(4+254)\equiv 258\equiv 2{\pmod {256}}$ 。

例如，8 位元有符號整數的值的範圍，如果規定為−128 到 127，則 126+125 將上溢位，結果是−5，即 $(126+125)\equiv 251\equiv -5{\pmod {256}}$ 。

對於 8 位元字長的有符號整數類型，以 28 即 256 為模，則

$$
{\begin{aligned}-128&\equiv 128{\pmod {256}}\\-127&\equiv 129{\pmod {256}}\\\vdots \\-2&\equiv 254{\pmod {256}}\\-1&\equiv 255{\pmod {256}}\\\end{aligned}}
$$

所以模 256 下的加減法，用 0, 1, 2,…, 254,255 表示其值，或者用−128, −127,…, −1, 0, 1, 2,…,127 是完全等價的。−128 與 128，−127 與 129，…，−2 與 254，−1 與 255 可以互換而加減法的結果不變。從而，把 8 位元（octet）的高半部分（即二進位的 1000 0000 到 1111 1111）解釋為−128 到−1，同樣也實現了模 256 的加減法，而且所需要的 CPU 加法運算器的電路實現與 8 位元無符號整數並無不同。

實際上對於 8 位元的儲存單元，把它的取值 [00000000,…, 11111111] 解釋為 [0, 255]，或者 [-1, 254]，或者 [-2, 253]，或者 [-128, 127]，或者 [-200, 55]，甚至或者 [500, 755]，對於加法硬體實現並無不同。

## 運算

### 加法

二補數系統數字的加法和一般加法相同，而且在運算完成後就可以看出結果的正負號，不需特別的處理。

正數與負數相加不會出現上溢錯誤，因為它們的和一定會小於加數。上溢錯誤只有在兩個正數或兩個負數相加時才可能發生，這時候最高有效位（正負號）會變成相反。

以 15 加 - 5 為例：

```
 11111 111（進位）
  0000 1111 (15)
+ 1111 1011 (-5)
-----------------
  0000 1010 (10)
```

由於加數和被加數都是 8 位元，因此運算結果也限制在 8 位元內。第 8 位元相加後產生的進位不考慮（因為不存在第 9 位元）的 1 被忽略，所以其結果為 10。而 15 + (-5) = 10，計算結果正確。

在以上計算式中，可以由進位列的最左側二個位元得知結果是否出現溢位。溢位就是數字的絕對值太大，以致於無法在指定的二進位位元個數來表示（在此例中，是超過 8 位元的範圍）。若進位列的最左側二個位元同為 0 或同為 1，表示結果正確，若是一個為 0，另一個為 1，表示出現溢位錯誤。也可以對此二個位元進行互斥或運算，結果為 1 時，表示出現溢位錯誤。以下以 7 + 3 的 4 位元加法說明溢位錯誤的情形。

```
 0111（進位）
  0111 (7)
+ 0011 (3)
------------
  1010 (−6)  結果不正確！
```

在此例中，進位列的最左側二個位元為 01，因此出現溢位錯誤。溢位的原因是 7 + 3 的結果 (10) 超過二補數系統 4 位元所可以表示的數字範圍 -8~7。

故為防止溢位錯誤，二補數在進行加法運算時通常將符號位進行複製後追加到最高位之前，即設二補數 B 的位數為 WIDTH，則 B′={B [WIDTH-1],B}。應注意此處 B′的位數為 WIDTH+1。
如上兩例用此方法進行計算：

```
  11 1111 111（進位）
   0 0000 1111 (15)
  +1 1111 1011 (-5)
-------------------
(1)0 0000 1010 (10)
```

由於 WIDTH+1=8+1=9，故而第十位的 1 同樣由於溢位而被省略，結果仍為 10。兩負數（符號位為 1）相加時同理。

```
    111（進位）
  0 0111 (7)
+ 0 0011 (3)
--------------
  0 1010 (10)  結果正確！
```

由於 WIDTH+1=4+1=5，故第五位的 0 仍為符號位，得結果正數 10（十進位）。

### 減法

減法通常轉化為加法進行運算，將減數與被減數的二補數進行加法運算，即可得出差。

### 乘法

乘法在電腦的世界裡其實就是不斷的做加法。

例如：3\*5=3+3+3+3+3=15

### 除法

除法就是相減。

例如：10/3=10-3-3-3=1mod3
而減法又可做二補數相加，所以所有四則運算的基礎都是由加法而來。

## 相關條目

* 補數
* 一補數
* 二進制
* 有符號數處理
* 加法器

## 參考資料