int num = 9;
float* pFloat = (float*)#
printf("%d\n", num); // 9
printf("%f\n", *pFloat); // 0.000000
*pFloat = 9.0f;
printf("%d\n", num); // 1091567616
printf("%f\n", *pFloat); // 9.000000
本文徹底揭開 IEEE 754 標準下浮點數的位元密碼。
32 位元 int,9 的二進位:
00000000 00000000 00000000 00001001 = 0x00000009
符號位 (1 bit) | 指數位 (8 bits) | 尾數/有效數字 (23 bits) S | E | M
數值公式:V = (-1)^S × 1.M × 2^(E - 127)(規格化數)
1.M,最高位 1 不存儲,節省 1 位精度(實際 24 位)。e = E - 127。E = 0, M = 0:±0 (S 決定正負)E = 0, M ≠ 0:非規格化數,V = (-1)^S × 0.M × 2^(-126),表示極接近 0 的數E = 255, M = 0:±無窮大E = 255, M ≠ 0:NaN (Not a Number)S = 0 E = 00000000 = 0 → 非規格化數 M = 000 0000 0000 0000 0000 1001
代入非規格化公式:
V = (-1)^0 × 0.00000000000000000001001₂ × 2^(-126) = 1.001₂ × 2^(-146) ≈ 1.125 × 10^(-44)
極小正數,%f 預設 6 位小數顯示為 0.000000。
9.0 = 1001.0₂ = 1.001₂ × 2^3S = 0M = 001 後補 20 個 0 → 001 0000 0000 0000 0000 0000E = 3 + 127 = 130 = 10000010₂0 10000010 001000000000000000000000x411000001091567616符號位 (1) | 指數位 (11) | 尾數 (52) 偏移量 1023,隱含前導 1,精度約 15-17 位十進位數字
| 陷阱 | 現象 | 對策 |
|---|---|---|
| 0.1 + 0.2 != 0.3 | 十進位無法精確表示為二進位有限小數 | 金融用定點數/十進位庫;比較用 epsilon |
| 大數吃小數 | 1e20 + 1 - 1e20 = 0 | Kahan 求和演算法、排序後累加 |
| NaN 傳染 | 任何與 NaN 運算結果為 NaN | isnan() 檢查、-ffast-math 謹慎使用 |
| 非規格化數效能懲罰 | x86 處理非規格化數慢 10-100 倍 | _MM_SET_FLUSH_ZERO_MODE 或編譯選項 |
| 型別懲罰 | 整數位元重讀為浮點數 (如開頭範例) | 嚴禁 reinterpret_cast/union 型別雙關,用 memcpy 或 std::bit_cast (C++20) |
std::bit_cast 安全轉換
#include <bit>
#include <cstdint>
float f = 9.0f;
uint32_t bits = std::bit_cast<uint32_t>(f); // 安全、無 UB、編譯期可執行
float f2 = std::bit_cast<float>(bits);
浮點數不是實數,而是有限精度的離散近似。掌握 IEEE 754 位元佈局、特殊值語意、精度邊界與現代轉換工具,是寫出數值穩健程式碼的前提。