JavaScript 中精度問題及解決思路彙總
導讀 | JavaScript 中的數字按照 IEEE 754 的標準,使用 64 位雙精度浮點型來表示。其中符號位 S,指數位 E,尾數位M分別佔了 1,11,52 位,並且在 ES5 規範 中指出了指數位E的取值範圍是 [-1074, 971]。 |
想用有限的位來表示無窮的數字,顯然是不可能的,因此會出現一些列精度問題:
- 浮點數精度問題,比如 0.1 + 0.2 !== 0.3
- 大數精度問題,比如 9999 9999 9999 9999 == 1000 0000 0000 0000 1
- toFixed 四捨五入結果不準確,比如 1.335.toFixed(2) == 1.33
浮點數精度和 toFixed 其實屬於同一類問題,都是由於浮點數無法精確表示引起的,如下:
(1.335).toPrecision(20); // "1.3349999999999999645"
而關於大數精度問題,我們可以先看下面這個程式碼片段:
// 能精確表示的整數範圍上限,S為1個0,E為11個0,S為53個1 Math.pow(2, 53) - 1 === Number.MAX_SAFE_INTEGER // true // 能精確表示的整數範圍下限,S為1個1,E為11個0,S為53個1 -(Math.pow(2, 53) - 1) === Number.MIN_SAFE_INTEGER // true // 能表示的最大數字,S為1個0,E為971,S為53個1 (Math.pow(2, 53) - 1) * Math.pow(2, 971) === Number.MAX_VALUE // true // 能表示的最接近於0的正數,S為1個0,E為-1074,S為0 Math.pow(2, -1074) === Number.MIN_VALUE // true
透過以上可以明白, [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER] 的整數都可以精確表示,但是超出這個範圍的整數就不一定能精確表示。這樣就會產生所謂的大數精度丟失問題。
首先考慮的是如何解決浮點數運算的精度問題,有 3 種思路:
- 考慮到每次浮點數運算的偏差非常小(其實不然),可以對結果進行指定精度的四捨五入,比如可以parseFloat(result.toFixed(12));
- 將浮點數轉為整數運算,再對結果做除法。比如0.1 + 0.2,可以轉化為(1*2)/3。
- 把浮點數轉化為字串,模擬實際運算的過程。
先來看第一種方案,在大多數情況下,它可以得到正確結果,但是對一些極端情況,toFixed 到 12 是不夠的,比如:
210000 * 10000 * 1000 * 8.2 // 17219999999999.998 parseFloat(17219999999999.998.toFixed(12)); // 17219999999999.998,而正確結果為 17220000000000
上面的情況,如果想讓結果正確,需要 toFixed(2),這顯然是不可接受的。
再看第二種方案,比如 number-precision 這個庫就是使用的這種方案,但是這也是有問題的,比如:
// 這兩個浮點數,轉化為整數之後,相乘的結果已經超過了 MAX_SAFE_INTEGER 123456.789 * 123456.789 // 轉化為 (123456789 * 123456789)/1000000,結果是 15241578750.19052
所以,最終考慮使用第三種方案,目前已經有了很多較為成熟的庫,比如 bignumber.js,decimal.js,以及big.js等。我們可以根據自己的需求來選擇對應的工具。並且,這些庫不僅解決了浮點數的運算精度問題,還支援了大數運算,並且修復了原生toFixed結果不準確的問題。
還有另外一個與 JavaScript 計算相關的問題,即 Math.round(x),它雖然不會產生精度問題,但是它有一點小陷阱容易忽略。下面是它的舍入的策略:
- 如果小數部分大於 0.5,則舍入到下一個絕對值更大的整數。
- 如果小數部分小於 0.5,則舍入到下一個絕對值更小的整數。
- 如果小數部分等於 0.5,則舍入到下一個正無窮方向上的整數。
所以,對 Math.round(-1.5),其結果為 -1,這可能不是我們想要的結果。
當然,上面提到的 big.js 等庫,都提供了自己的 round 函式,並且可以指定舍入規則,以避免這個問題。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2775214/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JavaScript中解決計算精度丟失的問題JavaScript
- 探尋 JavaScript 精度問題以及解決方案JavaScript
- zabbix 小問題解決彙總
- VNC常用操作及常見問題解決辦法彙總VNC
- JavaScript解決浮點數算數運算精度問題JavaScript
- frm-40654問題解決彙總
- oracle 資料庫解決問題思路總結Oracle資料庫
- mount命令詳解及常見問題彙總
- AIX問題解決思路AI
- 【長期更新】【Git】問題彙總 & 分析解決Git
- [長期更新][Git] 問題彙總 & 分析解決Git
- vmware ubuntu虛擬機器問題彙總解決Ubuntu虛擬機
- eclipse 中文亂碼問題解決方案彙總Eclipse
- 二、Git 問題彙總及處理Git
- mybatis常見庫及問題彙總MyBatis
- 微服務改造中解決跨庫問題的思路微服務
- goldengate 故障及解決方法彙總Go
- Android中handler問題彙總Android
- 記錄--前端金額運算精度丟失問題及解決方案前端
- MySQL 在併發場景下的問題及解決思路MySql
- MySQL在併發場景下的問題及解決思路MySql
- 頭條螢幕適配問題彙總及解決,這次你值得嘗試
- 對瀏覽器css相容性的學習理解及問題解決彙總瀏覽器CSS
- js算數運算精度問題解決方案JS
- javascript的物件問題及總結JavaScript物件
- Oracle 錯誤總結及問題解決 ORAOracle
- JS四則運算與四捨五入精度問題及解決方案JS
- 解決吞吐效能問題時的思路
- TongWeb下亂碼問題解決思路Web
- 巢狀ScrollView問題解決思路巢狀View
- redis中大key問題的解決思路Redis
- 開發微信小程式之HTTPS報錯常見問題彙總及解決方法微信小程式HTTP
- 學生資訊管理系統 (第二天 )技術彙總及問題解決
- CSS問題彙總CSS
- RecyclerView問題彙總View
- Redis問題彙總Redis
- nginx 問題彙總Nginx
- JavaScript 小數乘法運算精度問題JavaScript