或許不少人都遇到過,js 對小數的加、減、乘、除時常常獲得一些奇怪的結果!javascript
好比 :0.1 + 0.2 = 0.3 ?java
這麼一個簡單的計算,當你用js 計算時會發現結果是:0.30000000000000004 。這麼奇葩,簡直沒法理解!編程
那,爲何會這樣呢?瀏覽器
對於浮點數的四則運算,幾乎全部的編程語言都會有相似精度偏差的問題,只是 C++ / C# / Java 這些語言中已經封裝好了方法來避免精度的問題,而javascript 是一門弱類型的語言,從設計思想上就沒有對浮點數有個嚴格的數據類型,因此精度偏差的問題就顯得格外突出。編程語言
那爲何 0.1 + 0.2 這種簡單的運算,計算機還搞不定呢?那是由於,計算機不管作什麼運算,其實都是轉成二進制來運算的,由於它只能讀懂二進制,而不是十進制,因此咱們先把0.1 和 0.2轉換成二進制看看:spa
0.1 => 0.0001 1001 1001 1001... (無限循環)設計
0.2 => 0.0011 0011 0011 0011... (無限循環)code
咱們發現0.1和0.2轉化爲二進制以後,變成了一個無限循環的數字,這在現實生活中,無限循環咱們能夠理解,但計算機是不容許無限循環的,對於無限循環的小數計算機會進行舍入處理。進行雙精度浮點數的小數部分最多支持52位,因此二者相加以後獲得這麼一串0.0100110011001100110011001100110011001100110011001100 因浮點數小數位的限制而截斷的二進制數字,這時候,咱們再把它轉換爲十進制,就成了 0.30000000000000004。blog
找到緣由了,那應該怎麼處理呢?ip
方法一:指定要保留的小數位數(0.1+0.2).toFixed(1) = 0.3;這個方法toFixed是進行四捨五入的也不是很精準,對於計算金額這種嚴謹的問題,不推薦使用,並且不通瀏覽器對toFixed的計算結果也存在差別。
方法二:把須要計算的數字升級(乘以10的n次冪)成計算機可以精確識別的整數,等計算完畢再降級(除以10的n次冪),這是大部分編程語言處理精度差別的通用方法。
eg: (0.1*10 + 0.2*10) / 10 == 0.3
對於方法二能夠對四則運算分別做封裝:
/* ===== 浮點型數據的加、減、乘、除 ===== */ add(arg1, arg2) { // 加法 let r1, r2, m try { r1 = arg1.toString().split('.')[1].length } catch (e) { r1 = 0 } try { r2 = arg2.toString().split('.')[1].length } catch (e) { r2 = 0 } m = Math.pow(10, Math.max(r1, r2)) return (arg1 * m + arg2 * m) / m }, sub(arg1, arg2) { // 減法 let r1, r2, m, n try { r1 = arg1.toString().split('.')[1].length } catch (e) { r1 = 0 } try { r2 = arg2.toString().split('.')[1].length } catch (e) { r2 = 0 } m = Math.pow(10, Math.max(r1, r2)) n = (r1 >= r2) ? r1 : r2 return ((arg1 * m - arg2 * m) / m).toFixed(n) }, mul(arg1, arg2) { // 乘法 let m = 0 let s1 = arg1.toString() let s2 = arg2.toString() try { m += s1.split('.')[1].length } catch (e) { } try { m += s2.split('.')[1].length } catch (e) { } return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m) }, div(arg1, arg2) { // 除法 let t1 = 0 let t2 = 0 let r1 let r2 try { t1 = arg1.toString().split('.')[1].length } catch (e) { } try { t2 = arg2.toString().split('.')[1].length } catch (e) { } r1 = Number(arg1.toString().replace('.', '')) r2 = Number(arg2.toString().replace('.', '')) return (r1 / r2) * Math.pow(10, t2 - t1) }, /* ===== 浮點型數據的加、減、乘、除 ===== */