Home
探索 Uedu
學生控制台
註冊會員/登入
研究知情同意中心
教師控制台
課程設定
支援與訊息
Uptime 數據

UeduGPTs

--

Jupyters

4

UG26 CISOSE26
臺北 AQI 46 · 臺中 AQI 26 · 臺南 AQI 21 · 高雄 AQI 33

AI 回覆桌面通知

AI 助教回覆完成時顯示桌面通知

聊天訊息通知

同學在討論區發送訊息時通知

聲音通知

每當有新通知時播放提示音

數字系統與進位

數字系統與進位:電腦如何用 0 與 1 表達世界

從位值制出發,理解二進位、進位轉換、小數誤差,以及 2 的補數如何讓硬體用一個加法器搞定所有整數運算。

為什麼按下計算機,1 加 1 永遠不會等於 10?

如果你曾經把一張紙條密碼寫成「01001000 01101001」,或在網路上看過有人開玩笑說「世界上只有 10 種人,懂二進位的和不懂的」,那你已經碰到了數字系統(number system)的核心趣味。同一串符號「10」,在十進位裡是「十」,在二進位裡卻是「二」。一個符號要表示什麼數,從來不是天經地義,而是取決於我們約定好的「進位規則」。

電腦內部沒有十個手指頭可以數,它只有兩種狀態:有電壓、沒電壓;導通、不導通。於是這台機器選擇了二進位作為它的母語。要真正理解計算機如何儲存與運算,第一步就是搞懂:數字其實是一種「位置決定價值」的編碼遊戲。

計算的基礎概念示意圖

位值制:每一格都有自己的權重

我們從小用的十進位(decimal),本質是一套「位值制(positional notation)」。一個數字串,每一位的價值不只看它的符號,還要乘上它所在位置的「權重」。權重是基底(base/radix)的次方。

以十進位的 $3705$ 為例:

$$3705 = 3 \times 10^3 + 7 \times 10^2 + 0 \times 10^1 + 5 \times 10^0$$

換成基底 $b$,一個整數可以寫成:

$$N = \sum_{i=0}^{n-1} d_i \times b^{i}$$

其中 $d_i$ 是第 $i$ 位的數字,且每個 $d_i$ 必須滿足 $0 \le d_i < b$。這就是為什麼二進位只能用 0 和 1(基底 2,數字最大到 1);十六進位則需要額外的符號 A 到 F 來表示 10 到 15。

常見的四種進位制與其符號集合如下:

進位制 基底 可用符號
二進位(binary) 2 0, 1
八進位(octal) 8 0–7
十進位(decimal) 10 0–9
十六進位(hexadecimal) 16 0–9, A–F

小數的部分只是把指數延伸到負數。例如二進位的 $101.11_2$:

$$1 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 + 1 \times 2^{-1} + 1 \times 2^{-2} = 4 + 0 + 1 + 0.5 + 0.25 = 5.75_{10}$$

理解了「位值 = 數字 × 基底的次方」這一條原則,所有進位轉換就只是同一個公式的反覆套用。

為什麼電腦選二進位,而不是十進位?

一個很自然的疑問:既然人類用十進位這麼順手,為什麼不乾脆造一台用十進位的電腦?答案在於「可靠性」與「成本」。

電子元件最容易、最穩定地分辨的是「兩種狀態」:高電位與低電位、開與關。如果要讓單一電路穩定地分辨十個不同的電壓階層(例如 0V、0.5V、1V…),雜訊只要讓電壓飄移一點點,就可能把「3」誤判成「4」。而二進位只需要分辨「夠高」或「夠低」,容錯區間極大,極為抗雜訊。

此外,二進位天然對應布林邏輯(Boolean logic)的真與假,使得加法、比較、邏輯運算都能用一致的邏輯閘(logic gate)實現。歷史上確曾有十進位電腦(如早期的 ENIAC),但二進位在硬體簡潔度與可靠度上的壓倒性優勢,讓它成為現代計算的標準。

至於八進位與十六進位,它們不是給硬體用的,而是給「人」用的速記法。因為 $8 = 2^3$、$16 = 2^4$,每一個八進位位恰好對應 3 個二進位位,每一個十六進位位恰好對應 4 個二進位位。一長串 0 與 1 寫成十六進位會短得多、也不易看錯,這就是為什麼記憶體位址、色碼(如 #3C938A)幾乎都用十六進位表示。

值得留意的是,這種「人機分工」貫穿整個計算世界:硬體層永遠是二進位,但只要進位制的基底是 2 的次方,二進位與它之間的轉換就完全不需要做乘除運算,只要「分組」即可,幾乎零成本。反觀十進位與二進位之間就沒有這種整齊的對應關係(因為 10 不是 2 的次方),轉換時必須老老實實地做除法或乘法。這也解釋了為何工程師在面對位元層級的資料時,習慣切換到十六進位思考,而非十進位。

動手看一個例子:進位轉換

十進位轉二進位(整數)— 除以 2 取餘數,由下往上讀:

將 45 轉成二進位:
45 ÷ 2 = 22 ... 餘 1   ↑(最後讀,最高位)
22 ÷ 2 = 11 ... 餘 0   │
11 ÷ 2 =  5 ... 餘 1   │
 5 ÷ 2 =  2 ... 餘 1   │
 2 ÷ 2 =  1 ... 餘 0   │
 1 ÷ 2 =  0 ... 餘 1   ↓(最先算,但是最高位,反過來讀)

由下往上:45 = 101101₂
驗證:32 + 8 + 4 + 1 = 45 ✓

十進位小數轉二進位 — 乘以 2 取整數,由上往下讀:

將 0.625 轉成二進位:
0.625 × 2 = 1.25  → 取整數 1
0.25  × 2 = 0.5   → 取整數 0
0.5   × 2 = 1.0   → 取整數 1(小數歸零,結束)

由上往下:0.625 = 0.101₂
驗證:0.5 + 0 + 0.125 = 0.625 ✓

這裡藏著一個重要迷思的解答:許多十進位小數(如 $0.1$)在二進位中是「無限循環」的,無法精確表示。這正是為什麼 0.1 + 0.2 在多數程式語言裡會得到 0.30000000000000004——不是電腦算錯,而是浮點數先天無法精確存下 0.1。

二進位與十六進位互轉 — 每 4 位一組:

二進位      1101 1010 . 0110
              ↓    ↓      ↓
十六進位      D    A   .   6     →  DA.6₁₆

補數:用「加法」來做減法

到目前為止我們只談了正數。但電腦的硬體最好只會做一件事——加法。如果還要為「減法」「負數」另外造一套電路,成本很高。能不能讓「減去一個數」變成「加上另一個數」?這就是補數(complement)登場的地方。

考慮一個生活類比:時鐘是「模 12」的系統。要把時針從 8 點調回 5 點(減 3),你可以倒撥 3 小時,但也可以「正撥 9 小時」——因為 $8 + 9 = 17 \equiv 5 \pmod{12}$。在這個有限的循環系統裡,「減 3」與「加 9」效果完全相同。9 就是 3 在模 12 下的補數。

電腦的暫存器(register)也是有限位元的循環系統。在 $n$ 位元的世界裡,所有運算都是「模 $2^n$」——數值一旦超過上限就會繞回起點,就像時針走過 12 點又回到 1 點。我們可以借用時鐘的智慧,把負數編碼成某個正數,讓減法變成加法。歷史上人們嘗試過幾種編碼方案:最直覺的「符號-數值法」把最高位當純粹的正負號,但運算時要額外判斷符號、且有正負兩個零;「1 的補數」把負數定義為逐位取反,運算規則簡化了一些,卻仍留著正負零的尷尬。最終勝出、被現代 CPU 一致採用的,是2 的補數(two's complement)

深入:2 的補數運算機制與溢位

如何表示一個負數

在 $n$ 位元的 2 的補數系統中,一個負數 $-x$ 的編碼是 $2^n - x$。實務上有一個更好記的「翻轉加一」口訣:

取絕對值的二進位 → 每一位元取反(NOT) → 結果加 1。

以 8 位元表示 $-5$ 為例:

+5 的二進位:         0000 0101
逐位取反(1 的補數): 1111 1010
加 1:               1111 1011   →  這就是 -5

驗證:$1111\,1011_2 = 251_{10}$,而 $256 - 251 = 5$,確實對應 $-5$。

2 的補數的精妙之處,在於最高位(most significant bit)同時扮演「符號位」與「正常的位值」,只是它的權重是負的。對 8 位元而言:

$$\text{value} = -d_7 \times 2^7 + \sum_{i=0}^{6} d_i \times 2^i$$

代入 $1111\,1011$:$-128 + 64 + 32 + 16 + 8 + 0 + 2 + 1 = -5$ ✓。

為什麼減法就變成了加法

來算 $7 - 5$,也就是 $7 + (-5)$:

   0000 0111   (+7)
 + 1111 1011   (-5)
 -----------
 1 0000 0010
 ↑
 進位被丟棄(超出 8 位元)
   → 結果 0000 0010 = +2  ✓

關鍵在於:最高位產生的進位(carry-out)直接被「丟棄」,這正好實現了「模 $2^n$」的效果。整個過程硬體只用了一個加法器(adder),不需要任何專門的減法電路。這就是 2 的補數成為現代 CPU 標準的根本原因。

它還有一個額外優點:零只有一種表示法。相對地,早期使用過的「1 的補數」與「符號-數值法(sign-magnitude)」都存在 +0-0 兩種編碼,徒增比較與運算的複雜度。在 8 位元 2 的補數中,可表示範圍是 $-128$ 到 $+127$(負數比正數多一個,因為 0 佔據了正數那一側)。

溢位(overflow):當結果超出可表示範圍

有限位元意味著「天花板」。當兩數相加的真實結果超出 $[-128, +127]$,結果會「繞回」到錯誤的數值,這就是溢位。

來看 $100 + 50$(真實答案 150,已超過 127):

   0110 0100   (+100)
 + 0011 0010   (+50)
 -----------
   1001 0110   = -106 (在 2 的補數下)

兩個正數相加竟然得到負數!這是典型的有號數溢位。判定規則很俐落:

當兩個同號數相加,結果的符號卻與它們不同,就是溢位。

從硬體角度,CPU 用一條更精確的規則偵測溢位:

$$\text{Overflow} = C_{\text{in (MSB)}} \oplus C_{\text{out (MSB)}}$$

也就是「流入最高位的進位」與「流出最高位的進位」不相等時,溢位旗標(overflow flag)就會被設定。

請特別注意區分兩個容易混淆的概念:

  • 進位(carry):針對「無號數(unsigned)」運算的進位旗標,看最高位是否產生 carry-out。
  • 溢位(overflow):針對「有號數(signed)」運算,看符號是否錯亂。

同一次加法,無號解讀與有號解讀的「是否出錯」可能完全不同。CPU 同時維護 carry flag 與 overflow flag,由編譯器或程式設計師決定該採信哪一個。在 C/C++ 中,有號整數溢位是「未定義行為(undefined behavior)」,可能導致難以預測的安全漏洞——這也提醒我們,理解底層表示法不只是學術問題,更關乎程式的正確性與安全性。

重點回顧

  • 位值制是一切的基礎:任何進位制都遵循 $N = \sum d_i \times b^i$,「數字的價值 = 符號 × 基底的次方」,轉換不過是反覆套用同一公式。
  • 電腦用二進位是為了可靠:兩種狀態最抗雜訊、最易用邏輯閘實現;八進位與十六進位則是給人看的速記法($8=2^3$、$16=2^4$)。
  • 小數轉換可能無限循環:許多十進位小數(如 0.1)在二進位中無法精確表示,這是浮點數誤差的根源,不是電腦算錯。
  • 2 的補數讓減法變加法:用「翻轉加一」編碼負數,丟棄最高位進位即實現模 $2^n$ 運算,零只有一種表示,是現代 CPU 的標準。
  • 溢位與進位是兩回事:溢位看有號數的符號是否錯亂(同號相加得異號),進位看無號數的最高位 carry;CPU 兩個旗標分開維護。

深入探討(研究所視角)

從計算機結構的角度,2 的補數之所以勝出,本質是它把整數運算嵌入了一個有限交換環(finite commutative ring) $\mathbb{Z}/2^n\mathbb{Z}$。在這個環中,加法與乘法天然封閉、結合、分配,而「丟棄超出 $n$ 位元的高位」恰好就是環的模運算 $\bmod\ 2^n$。因此同一套硬體加法器既能正確處理無號數,也能正確處理有號數——有號與無號的差異只存在於「人類如何解讀那串位元」,而非運算本身。這個統一性是 1 的補數與符號-數值法都無法達成的,也是它們被淘汰的根本原因。

延伸到浮點數,IEEE 754 標準揭示了另一層深刻問題:實數是不可數無窮的,而任何有限位元的表示法只能表達可數的離散子集。於是「機器精度(machine epsilon)」$\epsilon$ 定義了相鄰兩個可表示浮點數之間的最小相對間隙,數值分析中誤差的累積、條件數(condition number)、災難性抵消(catastrophic cancellation)等議題都由此而生。前面提到的 0.1 + 0.2 ≠ 0.3 只是冰山一角;在大型科學計算或金融系統中,運算順序與表示誤差的交互作用,可能讓結果產生肉眼可見的偏差,這也是為什麼金額計算往往改用定點數或十進位浮點(decimal floating-point)。

最後值得連結的是資訊理論視角:一個數值需要多少位元,下界由其資訊熵(entropy)決定。$n$ 位元至多能區分 $2^n$ 種狀態,這條 $\log_2$ 的天花板貫穿了從資料壓縮、密碼學金鑰長度到雜湊碰撞機率的所有討論。當我們問「64 位元整數夠不夠用」「256 位元金鑰多安全」時,問的其實都是同一個問題:在有限位元的離散世界裡,我們能編碼多少種可能性。數字系統看似是入門課題,卻是通往計算理論深處的第一道門。

AI 共讀助教正在陪你讀:數字系統與進位:電腦如何用 0 與 1 表達世界
嗨!我是這篇文章的共讀助教,只根據〈數字系統與進位:電腦如何用 0 與 1 表達世界〉的內容回答。可以問我「解釋某段」「舉個例子」「出題考我」,或反白文中段落後點下方「解釋選取段落」。