JavaScript里精度损失是个非常头疼的毛病,典型的[0.1+0.2==0.30000000000000004]相信大家都有耳闻
这里抛出几个简单的方法,避免一部分0.30000000000000004的头疼情况
/**
* 加法运算,避免数据相加小数点后产生多位数和计算精度损失。
* @param num1加数1 | num2加数2
*/
function numAdd(num1, num2) {
var baseNum, baseNum1, baseNum2;
try {
baseNum1 = num1.toString().split(".")[1].length;
} catch(e) {
baseNum1 = 0;
}
try {
baseNum2 = num2.toString().split(".")[1].length;
} catch(e) {
baseNum2 = 0;
}
baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
return(num1 * baseNum + num2 * baseNum) / baseNum;
};
以上方法的核心思想是 —— 把小数 × 10ⁿ 换算成整数 -> 运算 -> 运算结果 ÷ 10ⁿ 还原数值
看起来毫无破绽的破解方法然并卵,因为我万万没想到
0.55*100==55.00000000000001
0.55/100==0.0055000000000000005
JavaScript 也真是够坑的,连 × 10ⁿ 的运算都不能让人安心
但是!方法还是用的,那就是js的一个替换方法, .replace()
小数转整数的过程,不用运算的方法,而改成处理字符串的方法. 数值转字符串 -> 记录小数点位置 -> 替换小数点[.replace(".", "")] -> 运算 -> 运算结果 ÷ 10ⁿ 还原数值
只要先做好乘法运算,其它3种运算再基于乘法运算,那就可以安全解决问题了
最后把这些内容装起来,就得到下面的公共对象:
var Utils = {
argAdd: function(arg1, arg2) {
// 加法函数
var _this = this,
r1 = 0,
r2 = 0,
m = 0;
try {
r1 = arg1.toString().split(".")[1].length
} catch(e) {}
try {
r2 = arg2.toString().split(".")[1].length
} catch(e) {}
m = Math.pow(10, Math.max(r1, r2))
return _this.argDiv((_this.argMul(arg1, m) + _this.argMul(arg2, m)), m)
},
argSubtr: function(arg1, arg2) {
// 减法函数
var _this = this,
r1 = 0,
r2 = 0,
m = 0;
try {
r1 = arg1.toString().split(".")[1].length
} catch(e) {}
try {
r2 = arg2.toString().split(".")[1].length
} catch(e) {}
m = Math.pow(10, Math.max(r1, r2));
return _this.argDiv((_this.argMul(arg1, m) - _this.argMul(arg2, m)), m)
},
argMul: function(arg1, arg2) {
// 乘法函数
var _this = this,
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)
},
argDiv: function(arg1, arg2) {
// 除法函数
var _this = this,
t1 = 0,
t2 = 0,
r1, 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 _this.argMul((r1 / r2), Math.pow(10, t2 - t1));
}
}
console.log(Utils.argAdd(0.1, 0.2))
console.log(0.1 + 0.2)
console.log(Utils.argSubtr(0.3, 0.2))
console.log(0.3 - 0.2)
console.log(Utils.argMul(0.55, 100))
console.log(0.55 * 100)
console.log(Utils.argDiv(0.55, 100))
console.log(0.55 / 100)
一句话总结:不要和小数玩运算