目錄

  1. 為什麼需要浮點數?
  2. 科學記號與二進位科學記號
  3. IEEE 754 格式總覽
  4. 單精度(Single Precision, 32-bit)
  5. 雙精度(Double Precision, 64-bit)
  6. 偏移指數(Biased Exponent)
  7. 正規化數(Normalized Numbers)
  8. 十進位轉 IEEE 754 範例
  9. IEEE 754 轉十進位範例
  10. 特殊值
  11. 非正規化數(Denormalized Numbers)
  12. 精度與範圍
  13. 常見陷阱與注意事項
  14. 浮點數加減乘除運算
  15. 捨入模式(Rounding Modes)
  16. 十六進位快速轉換技巧
  17. IEEE 754 與 MIPS 浮點指令
  18. 綜合練習題

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^(實際指數)