目錄
- 為什麼需要浮點數?
- 科學記號與二進位科學記號
- IEEE 754 格式總覽
- 單精度(Single Precision, 32-bit)
- 雙精度(Double Precision, 64-bit)
- 偏移指數(Biased Exponent)
- 正規化數(Normalized Numbers)
- 十進位轉 IEEE 754 範例
- IEEE 754 轉十進位範例
- 特殊值
- 非正規化數(Denormalized Numbers)
- 精度與範圍
- 常見陷阱與注意事項
- 浮點數加減乘除運算
- 捨入模式(Rounding Modes)
- 十六進位快速轉換技巧
- IEEE 754 與 MIPS 浮點指令
- 綜合練習題
1. 為什麼需要浮點數?
整數(Integer)只能表示離散的整數值,無法表示小數或非常大/非常小的數。例如:
- 圓周率 π = 3.14159...
- 光速 c = 3.0 × 10⁸ m/s
- 電子質量 = 9.109 × 10⁻³¹ kg
為了在電腦中表示這類數值,我們需要浮點數(Floating-Point Numbers)。
2. 科學記號與二進位科學記號
十進位科學記號
±d.ddd... × 10^exp
例如: - 123.456 = 1.23456 × 10² - 0.00789 = 7.89 × 10⁻³
二進位科學記號
±1.bbbb... × 2^exp
例如: - 十進位 5.75 = 二進位 101.11 = 1.0111 × 2² - 十進位 0.375 = 二進位 0.011 = 1.1 × 2⁻²
重點: 二進位正規化形式,整數部分永遠是 1(除了特殊情況),因此這個 1 不需要儲存,稱為隱藏位元(Hidden Bit / Implicit Leading 1)。
3. IEEE 754 格式總覽
IEEE 754 將浮點數分為三個欄位:
[Sign | Exponent | Mantissa (Fraction)]
符號 指數 尾數(小數部分)
| 欄位 | 說明 |
|---|---|
| Sign(符號位) | 0 = 正數,1 = 負數 |
| Exponent(指數) | 使用偏移碼(biased)表示 |
| Mantissa / Fraction(尾數) | 小數點後的位元(隱藏前導 1) |
兩種常用精度
| 項目 | 單精度(Single) | 雙精度(Double) |
|---|---|---|
| 總位元數 | 32 bits | 64 bits |
| 符號位 | 1 bit | 1 bit |
| 指數位 | 8 bits | 11 bits |
| 尾數位 | 23 bits | 52 bits |
| 偏移值(Bias) | 127 | 1023 |
| 指數範圍 | -126 ~ +127 | -1022 ~ +1023 |
4. 單精度(Single Precision, 32-bit)
31 30 23 22 0
┌───┬─────────┬────────────────────────┐
│ S │ Exponent│ Mantissa │
│1位│ 8 位 │ 23 位 │
└───┴─────────┴────────────────────────┘
公式
數值 = (-1)^S × 1.Mantissa × 2^(Exponent - 127)
- S:符號位(0 正,1 負)
- Exponent:8 位無號整數,範圍 0 ~ 255
- 0 和 255 為特殊用途
- 實際指數 = Exponent - 127(偏移值)
- Mantissa:23 位,表示 1.xxxxx 中小數點後的部分
5. 雙精度(Double Precision, 64-bit)
63 62 52 51 0
┌───┬─────────────┬──────────────────────────────────────┐
│ S │ Exponent │ Mantissa │
│1位│ 11 位 │ 52 位 │
└───┴─────────────┴──────────────────────────────────────┘
公式
數值 = (-1)^S × 1.Mantissa × 2^(Exponent - 1023)
- Exponent:11 位無號整數,範圍 0 ~ 2047
- 0 和 2047 為特殊用途
- 實際指數 = Exponent - 1023(偏移值)
- Mantissa:52 位
6. 偏移指數(Biased Exponent)
為什麼用偏移碼?
偏移碼讓指數永遠是非負整數,使得浮點數的大小比較可以像整數一樣直接比較位元模式。
計算方式
儲存的指數(Biased Exponent) = 實際指數 + Bias
單精度:Bias = 127
雙精度:Bias = 1023
範例
| 實際指數 | 單精度儲存值 (+ 127) | 二進位 (8-bit) |
|---|---|---|
| -126 | 1 | 0000 0001 |
| -1 | 126 | 0111 1110 |
| 0 | 127 | 0111 1111 |
| +1 | 128 | 1000 0000 |
| +127 | 254 | 1111 1110 |
注意:指數欄位為全 0(0)和全 1(255)保留給特殊值使用。
7. 正規化數(Normalized Numbers)
正規化數的形式為:
±1.Mantissa × 2^(Exponent - Bias)
前導的 1 是隱含的(implicit),不佔用儲存空間。因此 23 位的 Mantissa 實際上表示 24 位的有效數字。
例: 尾數欄位為 10110000000000000000000
實際值 = 1.10110000000000000000000₂ = 1 + 1/2 + 0/4 + 1/8 + 1/16 = 1.6875
8. 十進位轉 IEEE 754 範例
範例 1:將 -12.625 轉換為單精度 IEEE 754
步驟 1:決定符號位 - -12.625 是負數 → S = 1
步驟 2:將絕對值轉為二進位
整數部分 12:
12 ÷ 2 = 6 餘 0
6 ÷ 2 = 3 餘 0
3 ÷ 2 = 1 餘 1
1 ÷ 2 = 0 餘 1
→ 12₁₀ = 1100₂
小數部分 0.625:
0.625 × 2 = 1.25 → 取 1
0.25 × 2 = 0.5 → 取 0
0.5 × 2 = 1.0 → 取 1
→ 0.625₁₀ = 0.101₂
合併:12.625₁₀ = 1100.101₂
步驟 3:正規化(Normalize)
1100.101 = 1.100101 × 2³
步驟 4:計算偏移指數
實際指數 = 3
Biased Exponent = 3 + 127 = 130 = 10000010₂
步驟 5:取尾數(去掉隱藏的 1)
1.100101 → 尾數 = 100101
補齊 23 位:10010100000000000000000
最終結果:
S Exponent Mantissa
1 10000010 10010100000000000000000
合併:1 10000010 10010100000000000000000
十六進位:C1 4A 00 00 → 0xC14A0000
驗證:
(-1)¹ × 1.100101 × 2³
= -1 × 1.100101 × 8
= -1 × (1 + 1/2 + 0/4 + 0/8 + 1/16 + 0/32 + 1/64) × 8
= -1 × (1 + 0.5 + 0.0625 + 0.015625) × 8
= -1 × 1.578125 × 8
= -12.625 ✓
範例 2:將 0.1 轉換為單精度 IEEE 754
步驟 1:符號位 - 0.1 是正數 → S = 0
步驟 2:轉為二進位
0.1 × 2 = 0.2 → 0
0.2 × 2 = 0.4 → 0
0.4 × 2 = 0.8 → 0
0.8 × 2 = 1.6 → 1
0.6 × 2 = 1.2 → 1
0.2 × 2 = 0.4 → 0 ← 開始循環
0.4 × 2 = 0.8 → 0
0.8 × 2 = 1.6 → 1
0.6 × 2 = 1.2 → 1
...
0.1₁₀ = 0.0001 1001 1001 1001 1001 1001 1001...₂(無限循環)
步驟 3:正規化
0.00011001100110011... = 1.10011001100110011... × 2⁻⁴
步驟 4:計算偏移指數
Biased Exponent = -4 + 127 = 123 = 01111011₂
步驟 5:取尾數(23 位,截斷/四捨五入)
10011001100110011001101(經四捨五入)
最終結果:
S Exponent Mantissa
0 01111011 10011001100110011001101
合併:0 01111011 10011001100110011001101
十六進位:0x3DCCCCCD
重要觀察: 0.1 無法在 IEEE 754 中精確表示!
實際儲存的值約為 0.100000001490116...,這就是為什麼在程式中 0.1 + 0.2 ≠ 0.3 的原因。
範例 3:將 1.0 轉換為單精度 IEEE 754
步驟 1: S = 0(正數)
步驟 2: 1.0₁₀ = 1.0₂
步驟 3:正規化
1.0 = 1.0 × 2⁰
步驟 4:偏移指數
Biased Exponent = 0 + 127 = 127 = 01111111₂
步驟 5:尾數
1.0 → 尾數全為 0:00000000000000000000000
最終結果:
0 01111111 00000000000000000000000
十六進位:0x3F800000
範例 4:將 -0.75 轉換為單精度 IEEE 754
步驟 1: S = 1(負數)
步驟 2:
0.75 × 2 = 1.5 → 1
0.5 × 2 = 1.0 → 1
→ 0.75₁₀ = 0.11₂
步驟 3:正規化
0.11 = 1.1 × 2⁻¹
步驟 4:偏移指數
Biased Exponent = -1 + 127 = 126 = 01111110₂
步驟 5:尾數
1.1 → 尾數 = 10000000000000000000000
最終結果:
1 01111110 10000000000000000000000
十六進位:0xBF400000
範例 5:將 39.6875 轉換為雙精度 IEEE 754
步驟 1: S = 0(正數)
步驟 2:轉為二進位
整數部分 39:
39 ÷ 2 = 19 餘 1
19 ÷ 2 = 9 餘 1
9 ÷ 2 = 4 餘 1
4 ÷ 2 = 2 餘 0
2 ÷ 2 = 1 餘 0
1 ÷ 2 = 0 餘 1
→ 39₁₀ = 100111₂
小數部分 0.6875:
0.6875 × 2 = 1.375 → 1
0.375 × 2 = 0.75 → 0
0.75 × 2 = 1.5 → 1
0.5 × 2 = 1.0 → 1
→ 0.6875₁₀ = 0.1011₂
合併:39.6875₁₀ = 100111.1011₂
步驟 3:正規化
100111.1011 = 1.001111011 × 2⁵
步驟 4:偏移指數(雙精度 Bias = 1023)
Biased Exponent = 5 + 1023 = 1028 = 10000000100₂
步驟 5:尾數(補齊 52 位)
001111011 + 0000000000000000000000000000000000000000000(共 52 位)
= 0011110110000000000000000000000000000000000000000000
最終結果:
S Exponent Mantissa (52 bits)
0 10000000100 0011110110000000000000000000000000000000000000000000
十六進位:0x4043D80000000000
9. IEEE 754 轉十進位範例
範例 6:單精度 0x42F00000 轉十進位
步驟 1:轉為二進位
4 2 F 0 0 0 0 0
0100 0010 1111 0000 0000 0000 0000 0000
步驟 2:分離欄位
S = 0
Exponent = 10000101 = 133
Mantissa = 11100000000000000000000
步驟 3:計算實際指數
實際指數 = 133 - 127 = 6
步驟 4:計算數值
1.111 × 2⁶
= 1111000₂
= 64 + 32 + 16 + 8
= 120
符號為正 → 結果:+120.0
範例 7:單精度 0xC1C80000 轉十進位
步驟 1:轉為二進位
C 1 C 8 0 0 0 0
1100 0001 1100 1000 0000 0000 0000 0000
步驟 2:分離欄位
S = 1(負數)
Exponent = 10000011 = 131
Mantissa = 10010000000000000000000
步驟 3:計算實際指數
實際指數 = 131 - 127 = 4
步驟 4:計算數值
1.1001 × 2⁴
= 11001.0₂
= 16 + 8 + 1
= 25
符號為負 → 結果:-25.0
範例 8:雙精度轉十進位
0 10000000011 1010100000000000000000000000000000000000000000000000
分離欄位:
S = 0
Exponent = 10000000011₂ = 1027
Mantissa = 1010100000...0
計算實際指數:
實際指數 = 1027 - 1023 = 4
計算數值:
1.10101 × 2⁴
= 11010.1₂
= 16 + 8 + 2 + 0.5
= 26.5
結果:+26.5
10. 特殊值
IEEE 754 定義了幾個特殊值:
特殊值表格
| 符號 S | 指數(全部位元) | 尾數 | 代表的值 |
|---|---|---|---|
| 0 | 全 0 | 全 0 | +0 |
| 1 | 全 0 | 全 0 | -0 |
| 0 | 全 1 | 全 0 | +∞ |
| 1 | 全 1 | 全 0 | -∞ |
| 0 或 1 | 全 1 | 非 0 | NaN |
| 0 或 1 | 全 0 | 非 0 | 非正規化數 |
+0 和 -0(單精度)
+0:0 00000000 00000000000000000000000 = 0x00000000
-0:1 00000000 00000000000000000000000 = 0x80000000
在比較時,+0 == -0 為 true。
+∞ 和 -∞(單精度)
+∞:0 11111111 00000000000000000000000 = 0x7F800000
-∞:1 11111111 00000000000000000000000 = 0xFF800000
產生方式: - 1.0 / 0.0 = +∞ - -1.0 / 0.0 = -∞ - 任何正數 × ∞ = ∞
NaN(Not a Number,非數值)
例:0 11111111 10000000000000000000000 = 0x7FC00000(Quiet NaN)
例:0 11111111 00000000000000000000001 = 0x7F800001(Signaling NaN)
產生方式: - 0 / 0 - ∞ - ∞ - √(-1) - ∞ × 0
NaN 的重要特性: NaN ≠ NaN(NaN 不等於任何值,包括自身)
特殊值的雙精度表示
| 值 | 十六進位(雙精度) |
|---|---|
| +0 | 0x0000000000000000 |
| -0 | 0x8000000000000000 |
| +∞ | 0x7FF0000000000000 |
| -∞ | 0xFFF0000000000000 |
| NaN | 0x7FF8000000000000(例) |
11. 非正規化數(Denormalized / Subnormal Numbers)
當指數欄位為全 0 且尾數不為 0 時,使用不同的公式:
數值 = (-1)^S × 0.Mantissa × 2^(1 - Bias)
注意兩個差異: 1. 前導位元變成 0 而非 1(沒有隱藏的 1) 2. 指數固定為 1 - Bias(單精度為 -126,雙精度為 -1022)
非正規化數的目的
非正規化數填補了 0 和最小正規化數之間的間隙,讓數值可以「逐漸下溢(Gradual Underflow)」到零。
範例:最小正正規化數 vs 非正規化數(單精度)
最小正正規化數:
0 00000001 00000000000000000000000
= 1.0 × 2^(1-127) = 2⁻¹²⁶ ≈ 1.175 × 10⁻³⁸
最大非正規化數:
0 00000000 11111111111111111111111
= 0.11111111111111111111111₂ × 2⁻¹²⁶
≈ (1 - 2⁻²³) × 2⁻¹²⁶ ≈ 1.175 × 10⁻³⁸
最小正非正規化數:
0 00000000 00000000000000000000001
= 0.00000000000000000000001₂ × 2⁻¹²⁶
= 2⁻²³ × 2⁻¹²⁶
= 2⁻¹⁴⁹ ≈ 1.4 × 10⁻⁴⁵
12. 精度與範圍
單精度(32-bit)
| 特性 | 值 |
|---|---|
| 有效十進位位數 | 約 6-7 位 |
| 最大正規化數 | ≈ 3.4028 × 10³⁸ |
| 最小正正規化數 | ≈ 1.1755 × 10⁻³⁸ |
| 最小正非正規化數 | ≈ 1.4013 × 10⁻⁴⁵ |
| 1.0 與下一個可表示數的差(epsilon) | 2⁻²³ ≈ 1.19 × 10⁻⁷ |
雙精度(64-bit)
| 特性 | 值 |
|---|---|
| 有效十進位位數 | 約 15-16 位 |
| 最大正規化數 | ≈ 1.7977 × 10³⁰⁸ |
| 最小正正規化數 | ≈ 2.2251 × 10⁻³⁰⁸ |
| 最小正非正規化數 | ≈ 4.9407 × 10⁻³²⁴ |
| 1.0 與下一個可表示數的差(epsilon) | 2⁻⁵² ≈ 2.22 × 10⁻¹⁶ |
為什麼雙精度更好?
| 比較項目 | 單精度 | 雙精度 |
|---|---|---|
| 儲存空間 | 4 bytes | 8 bytes |
| 精確度 | ~7 位十進位 | ~16 位十進位 |
| 範圍 | 10⁻³⁸ ~ 10³⁸ | 10⁻³⁰⁸ ~ 10³⁰⁸ |
| 運算速度 | 較快 | 較慢(取決於硬體) |
| 適用場景 | 圖形處理、嵌入式 | 科學計算、金融 |
13. 常見陷阱與注意事項
陷阱 1:精度損失
0.1 + 0.2 ≠ 0.3(在浮點數中)
0.1₁₀ 和 0.2₁₀ 在二進位中都是無限循環小數,
儲存時被截斷導致微小誤差累積。
0.1 + 0.2 = 0.30000000000000004(在雙精度中)
陷阱 2:大數吞小數
單精度中:
16777216.0 + 1.0 = 16777216.0(不是 16777217.0!)
原因:16777216 = 2²⁴,此時精度只到整數位,
加上 1.0 會被四捨五入掉。
陷阱 3:比較浮點數
不要直接用 == 比較浮點數:
錯誤:if (a == 0.3) ...
正確:if (|a - 0.3| < epsilon) ... (epsilon 是一個很小的容差值)
陷阱 4:溢位與下溢
溢位(Overflow):結果太大,超出可表示範圍 → 變成 ±∞
下溢(Underflow):結果太小,接近零 → 變成非正規化數或 0
14. 浮點數加減乘除運算
浮點數的算術運算與整數截然不同,必須先處理指數對齊、再處理尾數運算。理解這些步驟,是學習浮點處理單元(FPU)與硬體電路設計的基礎。
14.1 浮點數加法/減法
演算流程(以 a + b 為例):
步驟 1:比較兩數指數,較小指數對齊到較大指數(小數右移、補零)
步驟 2:尾數相加(含隱藏位元 1)
步驟 3:將結果重新正規化(左移或右移,調整指數)
步驟 4:依捨入模式(rounding mode)對尾數做捨入
步驟 5:檢查是否溢位/下溢,組裝最終結果
範例 9:單精度 9.5 + 1.25 的加法
Step 0:將兩數先各自轉為 IEEE 754
9.5 = 1001.1₂ = 1.0011 × 2³
1.25 = 1.01₂ = 1.0100 × 2⁰
Step 1:對齊指數(將指數較小者右移)
將 1.25 對齊到 2³:
1.0100 × 2⁰ → 0.0010100 × 2³ (尾數右移 3 位)
Step 2:尾數相加
1.0011 0000 × 2³
+ 0.0010 1000 × 2³
─────────────────────
1.0101 1000 × 2³
Step 3:正規化檢查
1.0101 1000 的整數部分已為 1,不需再正規化。
Step 4:組裝結果
結果 = 1.01011 × 2³
= 1010.11₂
= 8 + 2 + 0.5 + 0.25
= 10.75 ✓
對應的 IEEE 754 單精度:
S = 0
Exponent = 3 + 127 = 130 = 10000010₂
Mantissa = 01011000000000000000000
結果:0 10000010 01011000000000000000000 = 0x412C0000
範例 10:單精度 0.5 × 2 加法(含正規化)
計算 1.5 + (-0.5) 來示範重新正規化:
1.5 = 1.1 × 2⁰
0.5 = 1.0 × 2⁻¹ → 對齊到 2⁰: 0.10 × 2⁰
由於是減法(運算元異號),尾數做減:
1.10 × 2⁰
- 0.10 × 2⁰
───────────
1.00 × 2⁰
整數部分仍為 1,無需正規化。結果 = 1.0
但若是 1.0 - 0.75:
1.0 = 1.000 × 2⁰
0.75 = 1.100 × 2⁻¹ → 對齊到 2⁰: 0.110 × 2⁰
1.000 × 2⁰
- 0.110 × 2⁰
───────────
0.010 × 2⁰
需要重新正規化(將整數部分 0 左移直到第一個 1):
0.010 × 2⁰ = 1.0 × 2⁻²
實際指數 = -2,Biased Exponent = -2 + 127 = 125 = 01111101
結果:0 01111101 00000000000000000000000 = 0x3E800000 = 0.25 ✓
14.2 浮點數乘法
演算流程(a × b):
步驟 1:符號 = Sa XOR Sb
步驟 2:指數相加並扣除一次 Bias
e = ea + eb - Bias
步驟 3:尾數(含隱藏 1)相乘
步驟 4:正規化(必要時右移 1 位、指數加 1)
步驟 5:捨入並組合結果
範例 11:單精度 6.0 × 2.5
6.0 = 1.10 × 2²
2.5 = 1.01 × 2¹
Step 1:符號 = 0 XOR 0 = 0
Step 2:指數
e = 2 + 1 = 3
Biased = 3 + 127 = 130 = 10000010
Step 3:尾數相乘(含隱藏 1)
1.10
× 1.01
───────
0.0110 ← 1.10 × 0.01
+ 1.1000 ← 1.10 × 1
─────────
1.1110
即 1.10 × 1.01 = 1.1110
Step 4:正規化
1.1110 整數部分為 1,已正規化,無需調整。
Step 5:組合結果
結果 = 1.1110 × 2³
= 1111.0₂
= 15.0 ✓
對應位元:
0 10000010 11100000000000000000000 = 0x41700000
範例 12:相乘後需要再正規化
計算 1.5 × 1.5 = 2.25:
1.5 = 1.1 × 2⁰
1.5 = 1.1 × 2⁰
尾數相乘:
1.1
× 1.1
──────
0.11
+ 1.10
──────
10.01
注意:結果 = 10.01₂,整數部分為 10!
重新正規化(指數 +1):
10.01 × 2⁰ = 1.001 × 2¹
對應結果 = 1.001 × 2¹ = 10.01₂ = 2.25 ✓
S = 0
Exponent = 1 + 127 = 128 = 10000000₂
Mantissa = 00100000000000000000000
結果:0 10000000 00100000000000000000000 = 0x40100000
14.3 浮點數除法
演算流程(a ÷ b):
步驟 1:符號 = Sa XOR Sb
步驟 2:指數相減並加回 Bias
e = ea - eb + Bias
步驟 3:尾數相除
步驟 4:正規化(必要時左移 1 位、指數減 1)
步驟 5:捨入並組合結果
範例 13:單精度 7.0 ÷ 2.0
7.0 = 1.11 × 2²
2.0 = 1.0 × 2¹
Step 1:符號 = 0 XOR 0 = 0
Step 2:指數
e = 2 - 1 = 1
Biased = 1 + 127 = 128 = 10000000
Step 3:尾數相除
1.11 ÷ 1.0 = 1.11
Step 4:組合結果
結果 = 1.11 × 2¹
= 11.1₂
= 3.5 ✓
對應位元:
0 10000000 11000000000000000000000 = 0x40600000
14.4 浮點運算的特殊情況
| 運算 | 結果 |
|---|---|
| 任何數 + ∞ | ∞ |
| ∞ - ∞ | NaN |
| 任何數 × ∞ | ±∞(依符號) |
| 0 × ∞ | NaN |
| 任何數 ÷ ∞ | 0 |
| ∞ ÷ ∞ | NaN |
| x ÷ 0(x≠0) | ±∞ |
| 0 ÷ 0 | NaN |
| 任何運算 + NaN | NaN |
15. 捨入模式(Rounding Modes)
當尾數運算結果超出可儲存的位數時,必須進行捨入。IEEE 754 定義了 4 種標準捨入模式:
| 模式 | 英文名稱 | 說明 |
|---|---|---|
| 就近捨入(預設) | Round to Nearest, ties to Even | 取最接近者;若距離相等,取尾位為偶數者 |
| 趨向 0 | Round toward Zero | 直接截斷(truncation) |
| 趨向 +∞ | Round toward +Infinity | 取較大者(向上捨入) |
| 趨向 -∞ | Round toward -Infinity | 取較小者(向下捨入) |
Guard、Round、Sticky 三個關鍵位元
硬體在做捨入時會在尾數後保留 3 個額外位元:
[尾數 23 bits] [G] [R] [S]
↑ ↑ ↑
Guard Round Sticky(之後位元的 OR)
- G(Guard):尾數最低位的下一位
- R(Round):再下一位
- S(Sticky):再之後所有位元的 OR
就近偶數(Round to Nearest, Even)的判斷:
| GRS | 動作 |
|---|---|
| 0xx | 截斷(往下捨) |
| 100 | 平手 → 看尾數 LSB:偶數則截斷,奇數則進位 |
| 101, 110, 111 | 進位(往上捨) |
範例:將 1.10101 1100 × 2⁰ 捨入到 4 位尾數
保留尾數:1.1010
GRS = 1, 1, 1+0+0=1(OR) = 111 → 進位
結果:1.1011 × 2⁰
範例:將 1.10101 1000 × 2⁰ 捨入到 4 位尾數(平手)
保留尾數:1.1010
GRS = 100 → 平手,看 LSB(=0,偶數)→ 截斷
結果:1.1010 × 2⁰
若改為 1.10111 1000:
保留尾數:1.1011
GRS = 100 → 平手,LSB=1(奇數)→ 進位
結果:1.1100 × 2⁰
16. 十六進位快速轉換技巧
考試時常需要快速將 IEEE 754 的二進位形式轉為十六進位。掌握以下技巧可大幅提升速度。
16.1 4-bit 對齊:S + Exponent + Mantissa
單精度共 32 位,剛好可分為 8 組 4 位元。關鍵是把符號位先「黏」到指數的最高位:
[S][E7 E6 E5 E4 E3 E2 E1 E0][M22 ... M0]
1 8 bits 23 bits
↓
[S E7 E6 E5][E4 E3 E2 E1][E0 M22 M21 M20][M19 M18 M17 M16] ...
nibble 1 nibble 2 nibble 3 nibble 4 ...
16.2 範例:將 3.14 的位元串快速轉為十六進位
已知 3.14 在單精度 IEEE 754 的位元為:
S = 0
E = 10000000
M = 10010001111010111000011
Step 1:將 32 位連寫(S → E → M,由高位到低位)
0 10000000 10010001111010111000011
Step 2:每 4 位重新切組(從最高位 bit 31 開始)
[0100] [0000] [0100] [1000] [1111] [0101] [1100] [0011]
4 0 4 8 F 5 C 3
Step 3:合併
3.14 → 0x4048F5C3 ✓
口訣: 切組時不要被「S | E | M」的分隔符干擾,先把 32 位連續寫成一條再切 4 位即可。
16.3 範例:將 0xC0490000 反查為十進位
Step 1:每個十六進位字符還原為 4 位二進位
C 0 4 9 0 0 0 0
1100 0000 0100 1001 0000 0000 0000 0000
Step 2:依 [1, 8, 23] 切分
S | E | M
1 | 10000000 | 10010010000000000000000
Step 3:解讀
S = 1(負數)
Exponent = 10000000₂ = 128 → 實際指數 = 128 - 127 = 1
Mantissa = 1.1001001₂
值 = -1 × 1.1001001 × 2¹
= -11.001001₂
= -(2 + 1 + 0.125 + 0.015625)
= -3.140625
結果:-3.140625(注意 0xC0490000 不是精確的 -π,是 -π 的近似截斷)
16.4 整數型「常數十六進位」記憶口訣
| 值 | 單精度 hex | 雙精度 hex |
|---|---|---|
| 0.0 | 0x00000000 | 0x0000000000000000 |
| 1.0 | 0x3F800000 | 0x3FF0000000000000 |
| 2.0 | 0x40000000 | 0x4000000000000000 |
| 0.5 | 0x3F000000 | 0x3FE0000000000000 |
| -1.0 | 0xBF800000 | 0xBFF0000000000000 |
| +∞ | 0x7F800000 | 0x7FF0000000000000 |
| NaN | 0x7FC00000 | 0x7FF8000000000000 |
口訣:指數欄位全 0 是 0/非正規化;全 1 是 ∞/NaN;正中間(0x3F8…/0x3FF…)就是 ±1.0。
17. IEEE 754 與 MIPS 浮點指令
MIPS 處理浮點數時,使用獨立的 32 個浮點暫存器 $f0~$f31,並有獨立的浮點協同處理器 Coprocessor 1(FPU)。
17.1 浮點暫存器
| 用途 | 暫存器 |
|---|---|
| 函式回傳值 | $f0~$f3 |
| 暫存(caller-saved) | $f4~$f10 |
| 函式參數 | $f12~$f14 |
| 一般用途(callee-saved) | $f20~$f30(偶數) |
雙精度數需要使用偶數編號的暫存器(如 $f0,會佔用 $f0+$f1)。
17.2 常用浮點指令
| 指令 | 範例 | 說明 |
|---|---|---|
add.s |
add.s $f0, $f1, $f2 |
單精度加 |
sub.s |
sub.s $f0, $f1, $f2 |
單精度減 |
mul.s |
mul.s $f0, $f1, $f2 |
單精度乘 |
div.s |
div.s $f0, $f1, $f2 |
單精度除 |
add.d |
add.d $f0, $f2, $f4 |
雙精度加(注意:偶數暫存器) |
mul.d |
mul.d $f0, $f2, $f4 |
雙精度乘 |
lwc1 |
lwc1 $f0, 0($t0) |
從記憶體載入單精度浮點 |
swc1 |
swc1 $f0, 0($t0) |
將浮點存回記憶體 |
ldc1 |
ldc1 $f0, 0($t0) |
載入雙精度浮點 |
mtc1 |
mtc1 $t0, $f0 |
從整數暫存器搬入浮點暫存器(位元複製,不轉換) |
mfc1 |
mfc1 $t0, $f0 |
從浮點暫存器搬出到整數暫存器 |
cvt.s.w |
cvt.s.w $f0, $f1 |
整數轉單精度 |
cvt.w.s |
cvt.w.s $f0, $f1 |
單精度轉整數 |
c.eq.s |
c.eq.s $f0, $f1 |
浮點比較 == |
c.lt.s |
c.lt.s $f0, $f1 |
浮點比較 < |
bc1t |
bc1t label |
若浮點旗標為真則跳轉 |
bc1f |
bc1f label |
若浮點旗標為假則跳轉 |
17.3 範例:計算圓面積
.data
pi: .float 3.14159
radius: .float 5.0
.text
main:
lwc1 $f4, pi # $f4 = 3.14159
lwc1 $f6, radius # $f6 = 5.0
mul.s $f8, $f6, $f6 # $f8 = r * r
mul.s $f12, $f4, $f8 # $f12 = pi * r * r
li $v0, 2 # syscall: print float
syscall
li $v0, 10
syscall
18. 綜合練習題
練習 1:十進位轉單精度 IEEE 754
將 6.25 轉換為 32 位 IEEE 754。
解答
步驟 1:S = 0(正數)
步驟 2:轉二進位
6 = 110₂
0.25 = 0.01₂
6.25 = 110.01₂
步驟 3:正規化
110.01 = 1.1001 × 2²
步驟 4:Biased Exponent = 2 + 127 = 129 = 10000001₂
步驟 5:Mantissa = 10010000000000000000000
結果:0 10000001 10010000000000000000000
十六進位:0x40C80000
練習 2:十進位轉單精度 IEEE 754
將 -19.5 轉換為 32 位 IEEE 754。
解答
步驟 1:S = 1(負數)
步驟 2:轉二進位
19 = 10011₂
0.5 = 0.1₂
19.5 = 10011.1₂
步驟 3:正規化
10011.1 = 1.00111 × 2⁴
步驟 4:Biased Exponent = 4 + 127 = 131 = 10000011₂
步驟 5:Mantissa = 00111000000000000000000
結果:1 10000011 00111000000000000000000
十六進位:0xC19C0000
練習 3:單精度 IEEE 754 轉十進位
將 0x41200000 轉為十進位。
解答
步驟 1:轉二進位
4 1 2 0 0 0 0 0
0100 0001 0010 0000 0000 0000 0000 0000
步驟 2:分離
S = 0
Exponent = 10000010 = 130
Mantissa = 01000000000000000000000
步驟 3:實際指數 = 130 - 127 = 3
步驟 4:數值
1.01 × 2³ = 1010₂ = 10₁₀
結果:+10.0
練習 4:單精度 IEEE 754 轉十進位
將 0xC2ED0000 轉為十進位。
解答
步驟 1:轉二進位
C 2 E D 0 0 0 0
1100 0010 1110 1101 0000 0000 0000 0000
步驟 2:分離
S = 1(負數)
Exponent = 10000101 = 133
Mantissa = 11011010000000000000000
步驟 3:實際指數 = 133 - 127 = 6
步驟 4:數值
1.1101101 × 2⁶ = 1110110.1₂
= 64 + 32 + 16 + 4 + 2 + 0.5
= 118.5
結果:-118.5
練習 5:雙精度 IEEE 754
將 -7.375 轉換為 64 位 IEEE 754。
解答
步驟 1:S = 1(負數)
步驟 2:轉二進位
7 = 111₂
0.375:
0.375 × 2 = 0.75 → 0
0.75 × 2 = 1.5 → 1
0.5 × 2 = 1.0 → 1
0.375 = 0.011₂
7.375 = 111.011₂
步驟 3:正規化
111.011 = 1.11011 × 2²
步驟 4:Biased Exponent = 2 + 1023 = 1025 = 10000000001₂
步驟 5:Mantissa(52 位)
1101100000000000000000000000000000000000000000000000
結果:
1 10000000001 1101100000000000000000000000000000000000000000000000
十六進位:0xC01D800000000000
練習 6:雙精度 IEEE 754 轉十進位
將下列雙精度位元模式轉為十進位:
0 10000000010 0110000000000000000000000000000000000000000000000000
解答
S = 0
Exponent = 10000000010₂ = 1026
Mantissa = 0110000000…0
實際指數 = 1026 - 1023 = 3
數值 = 1.011 × 2³ = 1011.0₂ = 11.0
結果:+11.0
練習 7:浮點數加法
計算 12.5 + 3.25,請寫出對齊、相加、正規化的完整過程,並給出單精度 IEEE 754 結果。
解答
12.5 = 1100.1₂ = 1.1001 × 2³
3.25 = 11.01₂ = 1.101 × 2¹
對齊(將 3.25 對齊到 2³):
1.101 × 2¹ → 0.01101 × 2³
相加:
1.10010 × 2³
+ 0.01101 × 2³
────────────────
1.11111 × 2³
無需重新正規化。
數值 = 1.11111 × 2³ = 1111.11₂ = 15.75 ✓
S = 0
Exponent = 3 + 127 = 130 = 10000010
Mantissa = 11111000000000000000000
結果:0 10000010 11111000000000000000000 = 0x41FC0000
練習 8:浮點數乘法
計算 2.5 × 4.0 並表示為單精度 IEEE 754。
解答
2.5 = 1.01 × 2¹
4.0 = 1.00 × 2²
符號 = 0 XOR 0 = 0
指數 = 1 + 2 = 3
尾數相乘:1.01 × 1.00 = 1.01
(無需重新正規化)
結果 = 1.01 × 2³ = 1010.0₂ = 10.0 ✓
Exponent = 3 + 127 = 130 = 10000010
Mantissa = 01000000000000000000000
結果:0 10000010 01000000000000000000000 = 0x41200000
練習 9:精度極限觀察
對於單精度浮點數:
(a) 2²⁴ + 1 的結果是多少?
(b) 2²⁵ + 1 的結果是多少?
(c) 2²⁵ + 2 的結果是多少?
解答
(a) 2²⁴ + 1
2²⁴ = 16777216
精度位數:23 + 1(隱藏位)= 24 位
在 2²⁴ 處,最低位剛好為 1.0,可精確表示 2²⁴+1。
結果:16777217 ✓
(b) 2²⁵ + 1
2²⁵ 處,相鄰可表示數的間距為 2²⁵⁻²³ = 4
1 < 2,會被四捨五入到 0,結果不變。
結果:16777216 × 2 = 33554432(不是 33554433!)
(c) 2²⁵ + 2
2 = 4/2,剛好在「平手」邊界。
依「就近偶數」規則,捨入到偶數倍:
結果:33554432(一樣!)
→ 在 2²⁵ 處,必須加上 ≥ 4 才會看得到變化。
練習 10:特殊值辨識
辨識以下單精度 IEEE 754 值:
| 二進位 | 答案 |
|---|---|
0 11111111 00000000000000000000000 |
? |
1 00000000 00000000000000000000000 |
? |
0 11111111 00001000000000000000000 |
? |
0 00000000 00000000000000000000001 |
? |
解答
| 二進位 | 答案 | |--------|------| | `0 11111111 00000000000000000000000` | **+∞** | | `1 00000000 00000000000000000000000` | **-0** | | `0 11111111 00001000000000000000000` | **NaN**(指數全1,尾數非0) | | `0 00000000 00000000000000000000001` | **最小正非正規化數** = 2⁻¹⁴⁹ |快速參考表
常用數值的單精度 IEEE 754
| 十進位 | 十六進位 | 二進位 |
|---|---|---|
| 0.0 | 0x00000000 | 0 00000000 00000000000000000000000 |
| 1.0 | 0x3F800000 | 0 01111111 00000000000000000000000 |
| -1.0 | 0xBF800000 | 1 01111111 00000000000000000000000 |
| 2.0 | 0x40000000 | 0 10000000 00000000000000000000000 |
| 0.5 | 0x3F000000 | 0 01111110 00000000000000000000000 |
| -0.5 | 0xBF000000 | 1 01111110 00000000000000000000000 |
| 0.25 | 0x3E800000 | 0 01111101 00000000000000000000000 |
| 3.14 | 0x4048F5C3 | 0 10000000 10010001111010111000011 |
| 10.0 | 0x41200000 | 0 10000010 01000000000000000000000 |
| 100.0 | 0x42C80000 | 0 10000101 10010000000000000000000 |
| +∞ | 0x7F800000 | 0 11111111 00000000000000000000000 |
| -∞ | 0xFF800000 | 1 11111111 00000000000000000000000 |
| NaN | 0x7FC00000 | 0 11111111 10000000000000000000000 |
附錄:轉換流程圖
十進位 → IEEE 754
十進位數
│
├─ 1. 判斷符號 → S 位
│
├─ 2. 取絕對值,轉二進位
│ ├─ 整數部分:連續除以 2 取餘數(逆序排列)
│ └─ 小數部分:連續乘以 2 取整數部分
│
├─ 3. 正規化為 1.xxxxx × 2^n
│
├─ 4. 計算偏移指數
│ ├─ 單精度:n + 127
│ └─ 雙精度:n + 1023
│
└─ 5. 取小數點後部分作為尾數,補 0 至所需位數
├─ 單精度:23 位
└─ 雙精度:52 位
IEEE 754 → 十進位
IEEE 754 位元模式
│
├─ 1. 分離 S / Exponent / Mantissa
│
├─ 2. 檢查特殊值
│ ├─ Exp 全 1,Mantissa 全 0 → ±∞
│ ├─ Exp 全 1,Mantissa 非 0 → NaN
│ ├─ Exp 全 0,Mantissa 全 0 → ±0
│ └─ Exp 全 0,Mantissa 非 0 → 非正規化數
│
├─ 3. 計算實際指數 = Exponent - Bias
│
├─ 4. 還原有效數 = 1.Mantissa
│
└─ 5. 數值 = (-1)^S × 1.Mantissa × 2^(實際指數)