处理浮点数精度缺失的运算
浮点数进行运算的时候会丢失精度(二进制无法精确表示),比如:0.1 + 0.2 !== 0.3
,那么可以先转成整数得出结果再然后算出浮点数,代码如下:
/**
* operationObj用于处理浮点数精度缺失的运算,
* 采用转换为整型运算之后再换成浮点数的形式
* 时间:2022-02-22
*
* 来源:javascript重难点实例精讲
* 源代码有几处没有考虑到reduce的第一个参数的特殊性,进行了修改和简化
*/
const operationObj = {
/**
* 处理传入的参数,不管传入的是数组还是以逗号分隔的参数都处理为数组
* @param {*} args
* @returns {*}
*/
getParam(args) {
return Array.prototype.concat.apply([], args)
},
/**
* 获取每一个数的乘数因子,根据小数位数计算
* 1.首先判断是否有小数点,如果没有,则返回1;
* 2.有小数点时,将小数位数的长度作为Math.pow()函数的参数进行计算
* 例如2的乘数因子为1,2.01的乘数因子为100
* @param {*} x
* @returns {number}
*/
multiplier(x) {
let parts = x.toString().split('.');
return parts.length < 2 ? 1 : Math.pow(10, parts[1].length);
},
/**
* 获取多个数据中最大的乘数因子
* 例如1.3的乘数因子为10,2.13的乘数因子为100
* 则1.3和2.13的最大的乘数因子为100
* @returns {*}
*/
correctionFactor() {
let args = Array.prototype.slice.call(arguments);
let argArr = this.getParam(args);
return argArr.reduce((accum, next, curIndex) => {
//获取第一个参数的乘数因子
if (curIndex === 1) {
accum = this.multiplier(accum);
}
let num = this.multiplier(next);
return Math.max(accum, num);
})
},
/**
* 加法运算
* @param {...any} args
* @returns {number}
*/
add(...args) {
let calArr = this.getParam(args);
//获取参与运算值的最大的乘数因子
let corrFactor = this.correctionFactor(calArr);
return calArr.map((item) => item * corrFactor).reduce((accnum, curr) => accnum + curr) / corrFactor;
},
/**
* 减法运算
* @param {...any} args
* @returns {number}
*/
subtract(...args) {
let calArr = this.getParam(args);
let corrFactor = this.correctionFactor(calArr);
return calArr.map((item) => item * corrFactor).reduce((accnum, curr) => accnum - curr) / corrFactor;
},
/**
* 乘法运算
* @param {...any} args
* @returns {*}
*/
multiply(...args) {
let calArr = this.getParam(args);
let corrFactor = this.correctionFactor(calArr);
return calArr.map((item) => item * corrFactor).reduce((accnum, curr) => Math.round(accnum) * Math.round(curr)) / Math.pow(corrFactor, calArr.length);
},
/**
* 除法运算
* @param {...any} args
* @returns {*}
*/
divide(...args) {
let calArr = this.getParam(args);
let quotient = calArr.reduce((accum, curr) => {
let corrFactor = this.correctionFactor(accum, curr);
//同时转换为整数参与运算
return Math.round(accum * corrFactor) / Math.round(curr * corrFactor);
})
return quotient;
}
}
console.log(operationObj.add(0.1, 0.2) === 0.3); //true
console.log(operationObj.subtract(0.1, 0.2)); //-0.1
console.log(operationObj.multiply(0.1, 0.2)); //0.02
console.log(operationObj.divide(0.1, 2)); //0.05