js在计算浮点数时可能不够准确,会产生舍入误差的问题,这是使用基于IEEE745数值的浮点计算的通病,并非ECMAScript一家,其他使用相同数值格式的语言也存在这个问题。
这里讲一下js浮点数加、减、乘、除的正确做法。
乘法运算
整数的乘法运算是准确的,这里我们将浮点数的乘法运算转化为整数乘法,然后除以10的他们小数位数之和次方,如0.03
乘以0.05
,转化为3 * 5 / 1e4
//乘法运算 0.03 * 0.05 变成3 * 5 / 10^4
function mul(a, b) {
var n = 0;
var c = a.toString(10);
var d = b.toString(10);
try {
n += c.split('.')[1].length;
} catch (f) {}
try {
n += d.split('.')[1].length;
} catch (f) {}
return (+c.replace('.', '')) * (+d.replace('.', '')) / Math.pow(10, n);
}
加法运算
这里我们将浮点数分别乘以小数位最大的之后,再相加,然后除以10的小数位数最大的次方,如0.03
加上0.5
,转化为3 + 50 / 1e2
//加法运算
function add(a, b) {
var c, d, n;
try {
c = (a + '').split('.')[1].length;
} catch(f) {
c = 0;
}
try {
d = (b + '').split('.')[1].length;
} catch(f) {
d = 0;
}
return e = Math.pow(10, Math.max(c, d)), (a * e + b * e)/ e;
}
减法运算
同加法,如0.03
减去0.5
,转化为3 - 50 / 1e2
//除法运算
function sub(a, b) {
var c, d, n;
try {
c = (a + '').split('.')[1].length;
} catch(f) {
c = 0;
}
try {
d = (b + '').split('.')[1].length;
} catch(f) {
d = 0;
}
return e = Math.pow(10, Math.max(c, d)), (a * e - b * e) / e;
}
除法运算
也类似加法,将两个数各自乘以10的他们小数位最大的次方,再相除,然后乘以1e(除数小数位 - 被除数小数位)
如0.03
除以0.5
,转化为3 / 50
再乘以1e-1
//除法运算
function dev(a, b) {
var c, d, e, f;
try {
c = (a + '').split('.')[1].length;
} catch (f) {
c = 0;
}
try {
d = (b + '').split('.')[1].length;
} catch (f) {
d = 0;
}
return e = (a + '').replace('.', '') , f = (b + '').replace('.', ''), mul(e / f, Math.pow(10, d - c));
}
测试代码:
console.log(sub(0.03, 0.5));//-0.2
console.log(add(0.03, 0.5));//0.53
console.log(mul(0.03, 0.5));//0.015
console.log(dev(0.03, 0.5));//0.06
输出结果 :