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

經典面試題:浮點數累加誤差與 0.01+0.02+...+1.0 精確計算

     編輯:關於C++

面試經典題:計算 0.01 + 0.02 + ... + 1.0,直接用浮點數循環累加會產生誤差(結果 ≈ 49.5 或 50.4999)。本文分析浮點數誤差原因,給出三種精確計算方案。

誤差演示

// 錯誤 1:double 循環
double sum = 0;
for (double d = 0.01; d <= 1.0; d += 0.01) sum += d;
// 結果:49.50000000000003

// 錯誤 2:float 循環
float sum = 0;
for (float d = 0.01f; d <= 1.0f; d += 0.01f) sum += d;
// 結果:50.499976608902216

誤差根因

  • 二進制無法精確表示 0.01:0.01₁₀ = 0.000000101000111101011100001010001111...₂(無限循環)。
  • 循環累加放大誤差:每次加法引入微小誤差,100 次累積顯著。
  • 循環條件判斷失敗:d <= 1.0 受誤差影響可能多跑/少跑一次。

方案一:整數累加再除法(推薦)

將問題轉化為整數運算:

// 0.01~1.0 對應 1~100
int sum = 0;
for (int i = 1; i <= 100; ++i) sum += i;
// 總和 = 5050
double result = sum / 100.0; // 50.5

或直接用等差數列求和公式:n*(a1+an)/2 = 100*101/2 = 5050。

方案二:定點數/定標運算

用整數表示「分」:

int sumCent = 0;
for (int i = 1; i <= 100; ++i) sumCent += i; // 5050 分
double result = sumCent / 100.0; // 50.5

方案三:BigDecimal 精確小數(Java)

BigDecimal sum = BigDecimal.ZERO;
BigDecimal step = new BigDecimal("0.01");
for (int i = 0; i < 100; ++i) {
    sum = sum.add(step);
}
// 結果:50.50
// 或直接:
BigDecimal result = new BigDecimal("0.01").multiply(new BigDecimal("5050")); // 50.50

方案四:修正浮點循環(原文方法)

每次累加後四捨五入到分:

double sum = 0, d = 0.01;
for (int i = 0; i < 100; ++i) {
    sum += d;
    sum = (int)(sum * 100) / 100.0; // 截斷到分
    d += 0.01;
}
// 結果:50.5

方案對比

方法精確度性能適用場景
整數累加/公式絕對精確O(1)/O(n)固定步長等差數列,首選
BigDecimal精確較慢金融/貨幣計算,任意精度需求
定點數精確快固定小數位業務(如價格分)
修正浮點較精確快必須用浮點循環的場景

最佳實踐原則

  1. 避免浮點數作循環變量:用整數索引,計算時轉換。
  2. 金額計算用整數分/BigDecimal:絕不直接用 float/double 存儲金額。
  3. 比較浮點數用 EPS:fabs(a-b) < 1e-9。
  4. 掌握等差數列求和公式:S = n*(a1+an)/2,O(1) 解決本題。

總結

本題核心教訓:浮點數不適合精確累加、不適合作循環控制變量。正確答案 50.5 可通過 100*101/2/100 = 50.5 一行公式得到。面試中先給出公式法,再討論浮點數誤差原理與工程替代方案(整數分、BigDecimal),展現從理論到工程的綜合能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved