JavaScript - 解決JavaScript根本的浮點數運算精準度問題(arbitrary-precision arithmetic)

經過前陣子的忙碌,總算有時間蓋步了,這次要蓋的不是步,而是限量在被發Bug後才知道的Javascript問題。到底是什麼問題呢?問題就是Javascript在進行浮點數運算時底層會發生捨去問題,造成結果預期是整數卻是.99999,例如:123.45 / 100 * 100,答案應該是123.45,但得出來結果竟然是123.44999999999999,不信的話可以打開F12試看看喔。

 問題的起因在於Round Error,Round Error就是有關四捨五入這般捨去進位的問題,出現像1/3=0.33333...這種除不盡的問題,就會有誤差,電腦是使用Binary Number來進行數值運算,在遇到除不盡的運算時會自動捨去後面幾位的Binary,再轉成十進位制顯示時就會出現錯誤,通常其他程式語言的DataType來自動處理,但Javascript底層沒有自動解決這問題,所以必須要自己處理。

要在Javascript上解決有幾種方法,最搞剛也最直覺的方式就是每進行一次浮點數運算,就先把有浮點數先轉成整數,然後記錄下該除多少位,經過一連串運算結果轉成整數後,最後在一次除以累積的位數,例如:123.45/100*100 => ((123.45*100)/100*100)/100 = 123.45。

其他方式可以去使用套件,因為這是個Javascript原生的問題,看來也不打算修,所以網路上很多人針對這個議題寫了許多的套件,像,總之撿現成就對了。

例如有個Big.js的Javascript函示庫就可以解決,以下為使用Big.js的範例:

<!DOCTYPE html>
<html>
<head>
 <title>Demo</title>
 <script src="big.js"></script>
 <script>
  var a = new Big(123.45);
  var b = new Big(100);
  var c = a.div(b).mul(b);
  alert(c);
 </script>
</head>
<body>

</body>
</html>



Big.js提供了add(), minus(), mul(), div() 加減乘除的Method可以使用,只要引入big.js後,然後宣告Big的浮點數物件,在使用Big.js提供的Method就可以進行正確的浮點數運算。



參考來源:

What Every Programmer Should Know About Floating-Point Arithmetic
StackOverflow - Is floating point math broken?
StackOverflow - How to multiply in Javascript? problems with decimals
StackOverflow - How to deal with floating point number precision in JavaScript?
Arbitrary-precision arithmetic

留言