js浮点数(小数)加减乘除丢失精度问题

147 阅读2分钟

记录工作中遇到的一个问题,后端接口接收的金额为数字类型,需要将字符串转数字,很简单的使用了Number(count)。

需求:需要上传数字类型,上传数字单位为分,需要将元转分

//很简单的想到
let res = Number(count) * 100
console.log(res)
//引发了一个问题当count="19.9"的时候,res不等于1990

1697436130272.png

查了资料后才发现:在 JavaScript 中整数和浮点数都属于Number数据类型,所有数字(包括整数)都是以 64 位浮点数形式储存。JavaScript 里的数字是采用IEEE 754标准的 64 位双精度浮点数,计算机进行计算的时候,会把数字转先换为二进制,进行运算之后再转换为十进制,但是运算过程中小数部分最多支持52位,超出就会出现运算精度问题,这也是为什么0.1+0.2=0.30000000000000004。

要想获取想要的结果可以先去掉小数点,再除以(两数倍数之积)

乘法:


//num1: 被乘数,num2: 乘数
function numMulti(num1, num2) {
    let baseNum = 0;
    try {
    	baseNum += num1.toString().split(".")[1].length;
    } catch (e) {
    }
    try {
    	baseNum += num2.toString().split(".")[1].length;
    } catch (e) {
    }
    return Number(num1.toString().replace(".", "")) * Number(num2.toString().replace(".", "")) / Math.pow(10, baseNum);
}

加法:

//num1: 被加数,num2: 加数
function numAdd(num1, num2) {
	let r1, r2, m;
	try {
		r1 = num1.toString().split('.')[1].length;
	} catch (e) {
		r1 = 0;
	}
	try {
		r2 = num2.toString().split('.')[1].length;
	} catch (e) {
		r2 = 0;
	}
	m = Math.pow(10, Math.max(r1, r2));
	return (num1 * m + num2 * m) / m;
}

减法:

//num1: 被减数,num2: 减数
function subtractive(num1, num2) {
	let r1, r2, m, n;
	try {
		r1 = num1.toString().split('.')[1].length;
	} catch (e) {
		r1 = 0;
	}
	try {
		r2 = num2.toString().split('.')[1].length;
	} catch (e) {
		r2 = 0;
	}
	m = Math.pow(10, Math.max(r1, r2));
	//动态控制精度长度
        n=(r1>=r2)?r1:r2;
	return ((num1*m-num2*m)/m).toFixed(n);
}

除法:

//num1: 被除数,num2: 除数
function numDiv(num1,num2){
	let t1 = 0, t2 = 0, r1, r2;
	try {
		t1 = num1.toString().split('.')[1].length;
	} catch (e) {}
	try {
		t2 = num2.toString().split('.')[1].length;
	} catch (e) {}
	r1 = Number(num1.toString().replace('.', ''));
	r2 = Number(num2.toString().replace('.', ''));
	return (r1 / r2) * Math.pow(10, t2 - t1);
}