在 JavaScript 中 0.1 + 0.2 會是多少?為什麼?如何避免相關問題?
2025年8月24日
JavaScript 與多數程式語言一樣,當我們把 0.1 + 0.2 時,會出現一個怪異的數字,如果沒有特別做處理的話,可能會產生錯誤;如果是做對數字精確度ㄧ要求高的產品,這是一定要避免的問題。也因此在 JavaScript 面試中這也是常考的基礎題。
0.1 + 0.2 會是多少?
會是 0.30000000000000004
為什麼會是 0.30000000000000004?
這不是 JavaScript 獨有的現象,而是使用二進制浮點運算的程式語言都會遇到的問題。而 JavaScript 中用到小數點時,因為 JavaScript 是採用 IEEE 754 六十四位元雙精度浮點數,所以會遇到這個問題。
在一般生活中,我們多數情況是使用十進位,而要能夠精確表達十進位,而 10 的質因數是 5 與 2,所以只有 1/2、1/4、1/5、1/8、1/10 這幾個數能夠被十進位的小數清楚表達;而像是 1/3、1/6、1/7、1/9 則不行。以 1/3 來說,我們知道會是 0.33333333 一路到無窮無盡。
而對於二進位制來說,只有 1/2、1/4、1/8 等可以被清楚表達,其他則會無窮無盡地延伸下去,然而因為電腦的記憶體有限,程式語言會分配給一個數字的記憶體也是有限,所以在精准度的表達下會有其限制,這也是導致 0.30000000000000004 這個怪異數字的原因。
該如何避免相關問題?
在 JavaScript 中有 toFixed 以及 toPrecision 等給數字操作的方法,讓我們能夠設定我們要的精確度,舉例來說,可以設定精確到小數第一位。因此
console.log((0.1 + 0.2).toFixed(1)); // 0.3
console.log((0.1 + 0.2).toPrecision(1)); // 0.3
不過這些方法都有一些限制,例如假如某個數是動態算出來的,就沒辦法預先在 toFixed 當中去寫要精確到第幾位數。因此比較多人會選擇用套件來處理。
社群中有一些熱門的 JavaScript 套件,以下幾個是 GitHub 上星星數多的
另外,近期有一個新的專案 nstr,該專案的解法專注在最終 UI 呈現上,如何避免這種怪異數字呈現的問題 (而不是專注在浮點數計算本身),大概一百行左右的程式碼,把各類的極端狀況都處理掉,蠻推薦可以一讀原始碼。
不用浮點數,或者改良浮點數計算
事實上在一些追求高精度數字的產業,例如金融產業,很多甚至會直接選擇不用浮點數,所有的計算都變成整數運算,完全避開浮點數的精度問題。例如 1 美元 5 分,比起用 1.05,會直接用 105。
由於浮點數的存在還是有其價值,假如直接用整數,也可能造成一些問題,所以業界也有做法是採用改良式的浮點數,例如 1.05 元變成 (1050000.0)。這樣可以精確表示 0.000001 到 9999999999.999999 之間的數值。
這做法如果超出上述的範圍,雖然還是能表示,但仍會有精度問題,所以範圍要拉多廣,端看系統需求而定。
有些程式語言 (例如 Java) 會有 BigDecimal 這種能解決精度問題的型別,但在空間和時間複雜度上可能會有額外的效能負擔,因此除非是真的需要到某個精度,不然通常是不必要的,改良版的浮點數方案通常就很夠用。
因此如何選擇,最終仍是要回到系統需求,根據實際需求和效能考量來選擇最適合的方案。