避免数据相加小数点后产生多位数和计算精度损失的几个见效甚少的方法

 

零点一加零点二不等于零点三

 

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)

 

一句话总结:不要和小数玩运算

 

参考资料:JS 四则运算(加减乘除小数运算)避免损失精度

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值