浮點數運算看似與數學課本上的實數運算無異,但由於電腦內部使用二進制和有限位數來儲存數字(遵循 IEEE 754 標準),在實際程式設計中會遇到許多意想不到的「陷阱」。
這些問題主要可以歸納為三大類:精度誤差、比較失效以及特殊值異常。以下我為你詳細拆解這些問題及其背後的原理。1. 精度誤差:為什麼 0.1 + 0.2 ≠ 0.3?
這是最經典也最讓人頭痛的浮點數問題。
- 現象:在大多數程式語言(如 Python, JavaScript, C++)中,計算
0.1 + 0.2得到的結果不是0.3,而是0.30000000000000004。 - 原因:二進制無法精確表示某些十進制小數。
- 就像十進制無法精確表示 1/3(只能寫成 0.333...),二進制也無法精確表示十進制的 0.1。0.1 在二進制中是一個無限循環小數(0.0001100110011...)。
- 由於記憶體有限(雙精度浮點數尾數僅 52 位),電腦必須將這個無限小數「截斷」或「捨入」,從而產生了微小的捨入誤差。
- 誤差累積:單次運算的誤差很小,但在循環累加(例如累加 10000 次 0.0001)或迭代計算中,這些微小誤差會不斷疊加,最終導致結果嚴重偏離理論值。
2. 比較失效:直接比較浮點數是危險的
由於上述的精度誤差,直接使用等於號(==)來判斷兩個浮點數是否相等,往往會導致邏輯錯誤。
- 現象:程式碼
if (0.1 + 0.2 == 0.3)的判斷結果通常是 False。 - 原因:左邊是經過運算後的近似值(
0.3000...04),右邊是字面量0.3的近似值,兩者在二進制底層並不完全相同。 - 正確做法:通常會定義一個極小的閾值(稱為 Epsilon,如
1e-9),判斷兩數之差的絕對值是否小於這個閾值。
3. 數量級差異導致的「吞噬」現象
當兩個數值量級相差懸殊時進行加減運算,較小的數可能會被「吃掉」。
- 現象:計算
1e16 + 1(即 10,000,000,000,000,000 + 1),結果仍然是1e16,那個1憑空消失了。 - 原因:對階時的精度丟失。
- 浮點數加減法需要先將指數對齊(讓小數點位置一致)。為了將小數的指數對齊到大數,小數的尾數必須向右移位。
- 當差距過大時,小數的有效數位會被移出儲存範圍,最終被捨棄,導致「大數吞小數」。
4. 特殊值與運算異常(Inf 與 NaN)
當運算結果超出浮點數能表示的範圍,或進行無意義的數學運算時,會產生特殊值。
- 溢出(Overflow)與無窮大(Inf):
- 當計算結果超過浮點數能表示的最大值(例如 float 約為 3.4e38),結果會變成 Inf(無窮大)。例如 1.0e30 * 1.0e30 會得到 Inf。
- 下溢(Underflow):
- 當結果過於接近 0,小於最小正浮點數時,會被視為 0.0。
- 非數字(NaN, Not a Number):
- 進行無意義的運算會產生 NaN,例如 0.0 / 0.0、∞ - ∞、√(-1) 或 sin(Inf)。
- 傳染性:NaN 具有傳染性,任何涉及 NaN 的運算(如 5 + NaN),結果都會變成 NaN,這在科學計算中常導致整個數據集失效。
- 除以零:
- 雖然整數除以零通常會導致程式崩潰(Exception),但在浮點數運算中,1.0 / 0.0 通常會返回 Inf 而不是直接崩潰,這有時會掩蓋程式邏輯錯誤。
📊 問題總結與對策表

理解這些問題能幫助你在編寫涉及數學運算的程式時,避開這些隱形的「地雷」,寫出更健壯的代碼。



















