資料表示法:位元、位元組與數值

二補數(two's complement)

/ tooz KOM-pluh-muhnt /

無號整數只能從零往上數,但真實程式也需要負數。難題在於:只有 0 和 1、寬度又固定,你要怎麼寫出負五?二補數就是幾乎每一台現代電腦採用的優雅解答,一旦你看懂這個訣竅,很難再想像有什麼比它更乾淨。

其想法是:保留普通的二進位位值,但讓「最高」位元的值變成負的。在一個 8 位元數字裡,位元位置原本值 128、64、32、16、8、4、2、1;在二補數裡,最高位改為值「負」128。所以 1111 1111 是 -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = -1,而 1000 0000 是純粹的 -128。一個方便的取負捷徑是:把每個位元翻轉,再加 1。要得到 -5,從 5(0000 0101)開始,翻轉成 1111 1010,加 1 得到 1111 1011,確實就是 -5。8 位元有號的範圍從 -128 到 +127。

二補數勝出,是因為它讓硬體變簡單:「同一套」加法電路對有號和無號數都管用——0xFF + 0x01 = 0x00,不管你把 0xFF 叫做「255」還是「-1」——而且零只有唯一一種表示法(所有位元為 0),不像舊方案。代價是一點小不對稱:負數比正數多一個,所以最負的值(如 8 位元的 -128,或 INT_MIN)沒有正的對應,對它取負會溢位。這一個小怪癖正是好幾個真實世界錯誤的來源,值得記住。

在 8 位元裡得到 -5:5 是 0000 0101;把所有位元翻轉成 1111 1010;加 1 得到 1111 1011 = 0xFB。驗算:1111 1011 按二補數讀是 -128+64+32+16+8+2+1 = -5。

取負 = 翻轉所有位元,再加一。最高位元帶負權重。

對最負的值取負(例如 -INT_MIN)無法表示,是有號溢位——在 C 裡是未定義行為,儘管硬體只會把那個負數原樣還給你。

又稱
2's complement二的補數