1. 程式人生 > >JS數字太大導致的精度丟失問題原因及解決方案

JS數字太大導致的精度丟失問題原因及解決方案

JS 數字丟失精度的原因

計算機的二進位制實現和位數限制有些數無法有限表示。就像一些無理數不能有限表示,如 圓周率 3.1415926…,1.3333… 等。JS 遵循 IEEE 754 規範,採用雙精度儲存(double precision),佔用 64 bit。如圖

這裡寫圖片描述

意義

  • 1位用來表示符號位
  • 11位用來表示指數
  • 52位表示尾數

浮點數,比如

0.1 >> 0.0001 1001 1001 1001…(1001無限迴圈)
0.2 >> 0.0011 0011 0011 0011…(0011無限迴圈)

此時只能模仿十進位制進行四捨五入了,但是二進位制只有 0 和 1 兩個,於是變為 0 舍 1 入。這即是計算機中部分浮點數運算時出現誤差,丟失精度的根本原因。

大整數的精度丟失和浮點數本質上是一樣的,尾數位最大是 52 位,因此 JS 中能精準表示的最大整數是 Math.pow(2, 53),十進位制即 9007199254740992。

大於 9007199254740992 的可能會丟失精度。

9007199254740992     >> 10000000000000...000 // 共計 53 個 0
9007199254740992 + 1 >> 10000000000000...001 // 中間 52 個 0
9007199254740992 + 2 >> 10000000000000...010 // 中間 51 個 0

實際上

9007199254740992 + 1 // 丟失
9007199254740992 + 2 // 未丟失
9007199254740992
+ 3 // 丟失 9007199254740992 + 4 // 未丟失

結果如圖

這裡寫圖片描述

解決方案

對於整數,前端出現問題的機率可能比較低,畢竟很少有業務需要需要用到超大整數,只要運算結果不超過 Math.pow(2, 53) 就不會丟失精度。

對於小數,前端出現問題的機率還是很多的,尤其在一些電商網站涉及到金額等資料。解決方式:把小數放到位整數(乘倍數),再縮小回原來倍數(除倍數),也就是說,儘量在業務中避免處理小數

個人總結

這是在我的業務中出現的一個問題,我們的業務後臺是用18位int型id來標記資料條目的,因此返回到前端就經常會獲取一個18位的number型變數,為了避免這個問題,我目前採用的方法就是與後臺溝通,統一採用string型別來傳輸此類資料,或者是在初始化資料時馬上轉化為字串,這樣前端在業務中全程都是使用字串來操作,就不會產生精度丟失問題。