浮點數陷阱


在進行運算時,很理所當然的認為 10 - 9.99 = 0.01,但實作時卻一直發生錯誤。
console 出來後發現,與原本預想的結果不相同,因此花了一些時間了解其中的原因。

// 預期結果
10 - 9.99 = 0.01
// 實際結果
10 - 9.99 = 0.009999999999999787

🌿 原因

JavaScript 中的所有數字,包含整數及小數,都是 Number 型別,並遵循 IEEE 754 標準,使用 64 位固定長度表示。此做法的優點是歸一化處理整數和小數,節省存盤空間。

我們平常學習的運算方式,是使用十進制處理。
然而 JavaScript 是先使用二進制來計算後,再轉換成十進制。浮點數再轉乘二進制造成無窮迴圈,進而產生誤差。

JavaScript 計算步驟

  • 先將數字轉成二進制
10 => 1010

9.99 => 1001.1111110101110000101000111101011100001010001111011
  • 運算
1010 - 1001.1111110101110000101000111101011100001010001111011 
= 0.0000001010001111010111000010100011110101110000101
  • 轉成十進制
0.0000001010001111010111000010100011110101110000101 => 0.009999999999999787

🌿 解法

1. 先乘以 100,四捨五入後再除以 100

需求為取至小數點後兩位時

let num = ((Number(10) * 100) - (Number(9.99) * 100)) / 100

Math.floor(num * Math.pow(10, 2)) / Math.pow(10, 2)

2. toPrecision(12)

12 能解決掉大部分 0001 和 0009 的問題

parseFloat(1.4000000000000001.toPrecision(12)) === 1.4  // True

🌿 參考資料


Photo by Evie S. on Unsplash


文章作者: Hobby Lee
版權聲明: 本部落格所有文章除特別聲明外,均採用 CC BY 4.0 許可協議。轉載請註明來源 Hobby Lee !
  目錄