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

浮點數陷阱:為什麼 (a+b)+c ≠ a+(b+c) 在程式語言中成立

     編輯:關於C

數學上加法滿足結合律,但在電腦浮點運算中,運算順序直接影響結果。本文透過 C# 實測,揭示整數溢位檢查與浮點精度捨入如何打破結合律,並解答 /checked 編譯選項下的行為差異。

整數溢位:checked vs unchecked

int a = int.MaxValue; // 2,147,483,647
int b = 1;
int c = -a;

Console.WriteLine(a + (b + c)); // 1
Console.WriteLine((a + b) + c); // unchecked: 1 / checked: OverflowException
  • b + c = 1 + (-MaxValue) = -2,147,483,646(安全)
  • a + b = MaxValue + 1 → 溢位:
    - unchecked (預設):環繞為 MinValue (-2,147,483,648),再加 c 得 1
    - checked:直接拋出 OverflowException

浮點精度:更隱蔽的差異

float a = float.MaxValue;  // ≈ 3.4e38
float b = -a;
float c = -1.0f;

Console.WriteLine(a + (b + c)); // 0
Console.WriteLine((a + b) + c); // -1

原因分析:

  1. b + c = -MaxValue - 1 ≈ -MaxValue(-1 相對 MaxValue 太小,被捨入)
  2. a + (b + c) ≈ MaxValue + (-MaxValue) = 0
  3. a + b = 0,再 + c = -1

浮點數有效位數有限(float 約 7 位十進位有效數字),大數吃小數導致資訊遺失,順序不同,遺失位置不同,結果自然不同。

思考題:float + /checked 結果?

答案:仍為 0 和 -1,無異常。

原因: /checked 僅影響整數溢位檢查。浮點運算遵循 IEEE 754 標準,溢位產生 Infinity,精度捨入屬正常行為,不受 checked 影響。

最佳實務建議

  1. 金融/精度敏感領域:使用 decimal(128 位,28-29 位有效數字)或定點數
  2. 科學計算:優先用 double(15-16 位有效數字),謹慎重排運算順序(如 Kahan 求和)
  3. 比較浮點數:永不使用 ==,改用 Math.Abs(a-b) < epsilon
  4. 整數運算:預設 unchecked 效能佳;安全關鍵路徑啟用 checked 或手動檢查

理解運算順序對數值結果的影響,是寫出健壯數值計算程式的必修課。下次見到 (a+b)+c,請三思:順序真的不重要嗎?

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