【Python自學】python 浮點數的誤差以及其解決方式

這篇整理 Python 中常見的「浮點數誤差」。當你看到 0.1 + 0.2 的結果不是剛好 0.3 時,不是你的數學壞掉,也不是 Python 在鬧脾氣,而是電腦儲存小數的方式造成的結果。

📘 Python 浮點數誤差:為什麼 0.1 + 0.2 不是 0.3?

在 Python 環境中,輸入以下程式碼:

例子一:0.1 + 0.2

# 浮點數的誤差 x = float(0.1 + 0.2) print(x)

執行結果:

0.30000000000000004

什麼?難道跟我們從小學的數學不一樣嗎?

再看看另外一個例子。

例子二:1 - 9 / 10

# 浮點數的誤差 x = float(1 - 9 / 10) print(x)

執行結果:

0.09999999999999998

蛤?根據我們粗淺但應該還算可靠的數學能力,1 - 9 / 10 應該等於 0.1

再怎麼樣,也不該跑出 0.09999999999999998 這種看起來很像電腦在碎念的數字。

例子三:直接印出 1 / 10

# 浮點數的誤差 x = float(1 / 10) print(x)

執行結果:

0.1

???

所以根據例子二和例子三,難道 1 - 9 / 10 不等於 1 / 10 嗎?

不是數學不一樣,而是電腦在處理小數時,會受到浮點數表示方式的限制。這就是所謂的「浮點數誤差」。

🧭 為什麼 float 計算有時候會不準?

Python 的 float 使用的是 IEEE 754 二進位浮點數標準來表示數字。

這件事不是只有 Python 會發生。只要是使用 IEEE 754 浮點數標準的程式語言,都可能遇到類似問題。

  • C 會這樣。
  • Java 會這樣。
  • JavaScript 也會這樣。
  • Python 當然也會這樣。

核心原因是:某些十進位小數,無法用二進位精準表示。

0.1 在十進位看起來很簡單,但在二進位中其實是無限循環小數。

🔢 十進位與二進位的差異

我們先從十進位的例子理解。

1 / 3 在十進位中是:

0.333333333333333333333333...

明明是一個很簡單的分數,但用十進位小數表示時,卻會變成無限循環小數。

同樣的道理,0.1 在二進位中也是無限循環小數。

0.1 的二進位表示

0.1 轉成二進位,大概會長這樣:

0.0001100110011001100110011001100110011001100110011...

後面的 0011 會一直重複,就像十進位中的 0.33333... 一樣。

但問題是,電腦不可能儲存無限長的小數。

電腦只能儲存有限位數。對常見的 IEEE 754 double precision 而言,大約有 53 位有效二進位精度,因此只能取一個近似值。

截斷或近似後的結果

因為電腦只能保存有限位數,所以 0.1 在內部會被存成一個非常接近但不是完全相等的數值。

0.1000000000000000055511151231257827021181583404541015625...

這就是浮點數誤差的來源。

簡單來說:
十進位的 0.1 對人類很簡單,但對使用二進位儲存小數的電腦來說,不一定能剛好表示。

🧪 為什麼 print(1 / 10) 看起來是 0.1?

你可能會問:既然 0.1 其實不是精準的 0.1,那為什麼直接印出 1 / 10 時,結果看起來是 0.1

這是因為 Python 在顯示浮點數時,會選擇一個比較簡潔、可讀的表示方式。

也就是說,Python 沒有每次都把內部完整近似值全部印出來,而是用一個足夠代表該浮點數的簡短結果顯示給你看。

print(1 / 10) # 0.1

但如果經過多個浮點數運算,誤差累積或顯示條件不同,就可能露出馬腳。

print(0.1 + 0.2) # 0.30000000000000004

🛠️ 浮點數誤差怎麼辦?三種常見解法

浮點數誤差很常見,但並不代表我們不能處理。以下整理三種常見方法。

方法 適合情境 重點
round() 一般顯示、日常計算結果 把誤差四捨五入掉。
Decimal 金額、帳務、高精度十進位運算 用字串建立 Decimal。
Fraction 需要保留精確分數的數學計算 直接用分數表示。

✅ 方法一:使用 round() 四捨五入

最常見也最直覺的方法,就是用 round() 將結果四捨五入。

result = round(0.1 + 0.2, 2) print(result)

執行結果:

0.3

因為誤差通常出現在很後面的小數位,對一般日常計算或顯示結果來說,只要把後面的誤差四捨五入掉,通常就夠用了。

round() 適合什麼情況?

  • 顯示計算結果。
  • 一般數學運算。
  • 不需要極高精度的日常程式。
round() 比較像是「修飾顯示結果」,不是真正消除浮點數儲存誤差。
如果是金額、帳務或高精度計算,不建議只靠 round()

✅ 方法二:使用 Decimal 處理高精度十進位

如果需要處理金額、帳務或比較精確的十進位計算,可以使用 Python 的 decimal 模組。

from decimal import Decimal # Decimal 的用法,注意參數建議使用字串型別 a = Decimal("0.1") b = Decimal("0.2") print(a + b)

執行結果:

0.3

為什麼 Decimal 可以,float 不行?

因為 Decimal 使用十進位,也就是 base 10 的方式來儲存與計算。

當它收到字串時,可以逐位解析文字,並建立精確的十進位表示。

也就是說,只要字串裡的數字是我們一般理解的十進位小數,Decimal 就能比較精確地表示它。

重要提醒:Decimal 要用字串建立

建議這樣寫:

Decimal("0.1")

不建議這樣寫:

Decimal(0.1)

因為 0.1 在傳進 Decimal 之前,就已經先被 Python 當成 float 處理過了。

from decimal import Decimal print(Decimal("0.1")) print(Decimal(0.1))

可能會看到類似結果:

0.1 0.1000000000000000055511151231257827021181583404541015625
重點一句話:
使用 Decimal 時,請優先用字串建立數字,例如 Decimal("0.1")。

✅ 方法三:使用 Fraction 進行分數計算

如果你想保留精確分數,而不是進入小數世界,可以使用 fractions 模組中的 Fraction

from fractions import Fraction a = Fraction(1, 10) # 代表 1/10 b = Fraction(2, 10) # 代表 2/10 print(a + b)

執行結果:

3/10

直接用分數計算,就不需要把數字轉成小數,也就不會遇到十進位小數轉二進位浮點數時造成的誤差。

Fraction 適合什麼情況?

  • 數學題需要保留分數形式。
  • 不希望結果變成小數。
  • 想進行精確的有理數運算。

這讓人想到以前學數學時,國小常常用小數表示答案;上了國中後,老師反而會要求很多答案用分數表示。

至於跟浮點數誤差有沒有直接關係,不一定。但分數表示確實可以在很多情況下保留精確結果。

📋 三種解法比較表

最後用表格整理 round()DecimalFraction 的差異。

方法 範例 優點 適合用途
round() round(0.1 + 0.2, 2) 簡單、快速、直覺 一般顯示結果
Decimal Decimal("0.1") 適合十進位精確計算 金額、帳務、高精度小數
Fraction Fraction(1, 10) 保留精確分數 數學運算、分數結果

🧠 小補充:不要直接比較浮點數是否相等

因為浮點數可能有微小誤差,所以實務上不建議直接這樣比較:

print(0.1 + 0.2 == 0.3)

執行結果可能是:

False

比較好的做法是允許一個很小的誤差範圍,或使用 Python 的 math.isclose()

import math print(math.isclose(0.1 + 0.2, 0.3))

執行結果:

True
如果只是判斷兩個浮點數是否「足夠接近」,math.isclose() 是很實用的工具。

✅ 小結

Python 的浮點數誤差不是 bug,而是二進位浮點數表示方式造成的結果。

  • float 使用 IEEE 754:用二進位浮點數表示小數。
  • 0.1 在二進位中是無限循環小數:電腦只能儲存近似值。
  • 0.1 + 0.2 可能不是剛好 0.3:因為內部近似值計算後會出現微小誤差。
  • round():適合一般顯示結果。
  • Decimal:適合金額、帳務、高精度十進位計算。
  • Fraction:適合需要保留精確分數的數學運算。
  • math.isclose():適合比較兩個浮點數是否足夠接近。
0.1 + 0.2 → 電腦用二進位近似儲存 → 計算後產生極小誤差 → 顯示為 0.30000000000000004
最後用一句話記住:
浮點數不是不會算,而是它用二進位近似表示小數,所以某些十進位小數無法被完美儲存。

留言

這個網誌中的熱門文章

麻將新手必看!不知道聽什麼牌怎麼辦?超多種實戰聽牌範例,教你怎麼判斷胡牌機會

麻將教學懶人包|從規則到牌理的完整觀念整理(附實戰心得)

【新訓入伍】義務役新兵必看!入伍報到必備清單整理|2026年更新