補碼是現代電腦系統中有號整數的標準表示法。本文從歷史動機、數學本質、硬體實作三個維度,深度解析為什麼補碼能將減法轉化為加法,並統一處理正負數運算。
1 + (-1) = 00000001 + 10000001 = 10000010 = -2 ❌+0 (00000000), -0 (10000000)核心洞見:模 N 系統中,a + b ≡ 0 (mod N) ⟹ b 是 a 的補數。
以 8 位元為例 (N = 256):
1 的補碼:256 - 1 = 255 = 11111111₂-1 即 255 (模 256 意義下)1 + (-1) = 1 + 255 = 256 ≡ 0 (mod 256) ✅| 數值 | 8 位元補碼 | 計算方式 |
|---|---|---|
| +127 | 01111111 | 直接二進位 |
| +1 | 00000001 | 直接二進位 |
| 0 | 00000000 | 唯一零表示 |
| -1 | 11111111 | 256-1=255 或 取反+1 |
| -127 | 10000001 | 256-127=129 |
| -128 | 10000000 | 256-128=128 (無對應正數) |
快速手算:正數直接寫;負數 → 寫絕對值二進位 → 取反 → 加 1。
對任意 a, b ∈ [-128, 127],其補碼表示 A, B ∈ [0, 255]:
A ≡ a (mod 256)
B ≡ b (mod 256)
A + B ≡ a + b (mod 256)
硬體只需計算 A + B 取低 8 位,結果自動為 a+b 的補碼表示。無需區分正負、無需減法器。
SUB 內部實作為 ADD 被減數, 減數的補碼n 位元補碼範圍:[-2ⁿ⁻¹, 2ⁿ⁻¹ - 1]
[-128, 127] (256 個值)[-32768, 32767][-2147483648, 2147483647]原因:零佔用一個編碼 (000...0),剩餘 2ⁿ-1 個編碼無法平均分給正負數,負數多一個 (-2ⁿ⁻¹ 無對應正數)。
& | ^ ~ << >>) 直接作用於補碼位模式#include <stdio.h>
#include <limits.h>
int main() {
printf("INT_MAX = %d (0x%X)\n", INT_MAX, INT_MAX);
printf("INT_MIN = %d (0x%X)\n", INT_MIN, INT_MIN);
int a = -1;
printf("-1 = 0x%X\n", a); // 0xFFFFFFFF
// 補碼驗證:~x + 1 == -x
for (int x : {1, 42, -5, 100}) {
printf("%d: ~x+1=%d, -x=%d %s\n",
x, ~x+1, -x, (~x+1 == -x) ? "✓" : "✗");
}
return 0;
}
補碼是模算術在有限位寬下的自然投影。它將減法轉化為加法,消除雙零,讓 CPU 只需一個加法器即可完成所有整數運算。這是計算機科學中「數學抽象指導硬體設計」最優雅的範例之一。理解補碼,就理解了有號整數運算的本質。