js中進行數字計算時候,會出現精度偏差的問題。先來看一個實例:html
console.log(0.1+0.2===0.3);//false編程
console.log(0.1+0.1===0.2);//true編程語言
上面第一個的輸出會超出咱們的常識,正常應該爲true,這裏爲何會是false呢,直接運行會發現0.1+0.2在js中計算的結果是:函數
console.log(0.1+0.2);//輸出0.30000000000000004this
這對於浮點數的四則運算(加減乘除),幾乎全部的編程語言都會出現上面相似的精度偏差問題,只是大部分語言都處理封裝了避免偏差的方法。對於js而言,因爲它是一門弱類型的語言,因此並無對浮點數的運算有解決的封裝方法,這能咱們本身來解決。這裏爲何會出現這個精度偏差呢?prototype
浮點數產生的緣由 htm
咱們首先就想到計算機能讀懂的是二進制,因此咱們進行運算的時候,其實是把數字轉換爲了二進制進行的,因此咱們把0.1和0.2轉換爲二進制:blog
0.1 => 0.0001 1001 1001 1001..(無限循環)it
0.2 => 0.0011 0011 0011 0011…(無限循環)io
這裏能夠看出轉換爲二進制是一個無限循環的數字,單在計算機中對於無限循環的數字會進行舍入處理的,進行雙精度浮點數的小數部分最多支持52位。而後把兩個2進制的數進行運算得出的也是一個二進制數值,最後再把它轉換爲十進制。保留17位小數,因此0.1+0.2的值就成了 0.30000000000000004。 0.1+0.1的值成了0.20000000000000000,全是0的時候能夠省略,就成了0.2
解決浮點數精度偏差的辦法
最簡單的處理,經過toFixed方法,
console.log(parseFloat(0.1+0.2).toFixed(1));//輸出0.3
說明:經過toFixed(num)方法來保留小數,其中num爲保留小數的位數,這個方法是根據四捨五入來保留小數的,因此計算的結果並非最精確的。因此咱們須要採用其它方法來實現,經過Number.prototype的屬性進行添加,以下:
js加法:
//加法函數
function accAdd(arg1, arg2) {
var 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;
} //給Number類型增長一個add方法,使用時直接用 .add 便可完成計算。
Number.prototype.add = function(arg){
return accAdd(arg, this);
};
console.log(0.1.add(0.2).add(0.3));//等價於0.1+0.2+0.3,輸出0.6
console.log(0.1+0.2+0.3);//輸出0.6000000000000001
js減法:
//減法函數
function Subtr(arg1, arg2) {
var 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 parseFloat(((arg1 * m - arg2 * m) / m).toFixed(n));
}
Number.prototype.sub = function(arg) {
return Subtr(this, arg);
};
console.log(0.6.sub(0.2).sub(0.3));//等價於0.6-0.2-0.3 輸出0.1
console.log(0.6-0.2-0.3);//輸出:0.09999999999999998
js乘法:
//乘法函數
function accMul(arg1, arg2) {
var m = 0,
s1 = arg1.toString(),
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);
}
Number.prototype.mul = function (arg) {
return accMul(arg, this);
};
console.log(0.1.mul(0.2).mul(0.3)); //等價於0.1 * 0.2 * 0.3 輸出0.006
console.log(0.1 * 0.2 * 0.3); //輸出:0.006000000000000001
js除法:
//除法函數
function accDiv(arg1, arg2) {
var t1 = 0,
t2 = 0,
r1, r2;
try {
t1 = arg1.toString().split(".")[1].length;
} catch(e) {}
try {
t2 = arg2.toString().split(".")[1].length;
} catch(e) {}
with(Math) {
r1 = Number(arg1.toString().replace(".", ""));
r2 = Number(arg2.toString().replace(".", ""));
return(r1 / r2) * pow(10, t2 - t1);
}
}
Number.prototype.div = function (arg) {
return accDiv(this, arg);
};
console.log(0.6.div(0.2).div(0.1)); //等價於0.6 / 0.2 / 0.1 輸出30
console.log(0.6 / 0.2 / 0.1); //輸出:29.999999999999993
原文出處:https://www.cnblogs.com/ranyonsue/p/11378200.html