首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言問答

C語言浮點數無法精確存儲的根本原因:IEEE 754 與二進制表示局限

     編輯:C 語言問答

核心結論

十進制小數多數無法用有限二進制小數精確表示,正如 1/3 在十進制中為 0.333... 無限循環,0.1 在二進制中為 0.0001100110011... 無限循環。

IEEE 754 雙精度 (double) 佈局

符號位 (1) | 指數位 (11) | 尾數位 (52)  ← 共 64 位
  S           EEEEEEEEEEE    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
  • 值 = (-1)^S × 1.M × 2^(E-1023) (正規數)。
  • 52 位尾數 ≈ 15~17 位十進制有效數字。
  • float (單精度) 23 位尾數 ≈ 6~9 位十進制數字。

經典案例:0.1 + 0.2 ≠ 0.3

#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**

工程應對策略

  1. 金融/貨幣計算:用 **整數分單位** (存分而非元) 或 **定點數庫** / **十進制浮點數** (_Decimal64 GCC 擴展、decimal C#)。
  2. 比較浮點數:fabs(a - b) < EPSILON (相對/絕對誤差結合)。
  3. 輸出格式化:printf("%.2f", val) 顯示兩位小數,掩蓋尾部噪聲。
  4. 避免累積誤差**:Kahan 求和、成對求和、高精度庫 (MPFR、Boost.Multiprecision)。

深度閱讀

  • David Goldberg: What Every Computer Scientist Should Know About Floating-Point Arithmetic (ACM Computing Surveys, 1991) —— 必讀經典。
  • IEEE 754-2019 標準文件。
  • man 7 float (Linux) 查看系統浮點數環境。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved