十進制小數多數無法用有限二進制小數精確表示,正如 1/3 在十進制中為 0.333... 無限循環,0.1 在二進制中為 0.0001100110011... 無限循環。
double) 佈局符號位 (1) | 指數位 (11) | 尾數位 (52) ← 共 64 位
S EEEEEEEEEEE MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
(-1)^S × 1.M × 2^(E-1023) (正規數)。float (單精度) 23 位尾數 ≈ 6~9 位十進制數字。#include <stdio.h>
int main() {
double a = 0.1, b = 0.2;
printf("%.17f\n", a + b); // 0.30000000000000004
printf("%.17f\n", 0.3); // 0.29999999999999999
return 0;
}
兩者二進制近似值相加,誤差累積導致結果非精確 0.3。
| 誤區 | 事實 |
|---|---|
「double 是 32 位」 | double 64 位,float 32 位 |
| 「CPU 字長導致對階丟失」 | 對階在運行時由硬體/軟體完成,**精度損失源於初始表示近似**,非對階過程 |
「用 long double 就能精確」 | x86 long double 80 位 (64 位尾數) 精度更高,**但仍無法精確表示 0.1** |
_Decimal64 GCC 擴展、decimal C#)。fabs(a - b) < EPSILON (相對/絕對誤差結合)。printf("%.2f", val) 顯示兩位小數,掩蓋尾部噪聲。man 7 float (Linux) 查看系統浮點數環境。