一、数学运算
问题:0.1 + 0.2 = 0.30000000000000004
在JavaScript中,整数和浮点数都属于Number类型,它们都统一采用64位浮点数进行存储。因浮点数的精度有限,会出现精度丢失,舍入误差问题。
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) => {let num = this.multiplier(next);return Math.max(accum, num);}, 1);},/*** 加法运算* @param args* @returns {number}*/add(...args) {let calArr = this.getParam(args);// 获取参与运算值的最大乘数因子let corrFactor = this.correctionFactor(calArr);let sum = calArr.reduce((accum, curr) => {// 将浮点数乘以最大乘数因子,转换为整数参与运算return accum + Math.round(curr * corrFactor);}, 0);// 除以最大乘数因子return sum / corrFactor;},/*** 减法运算* @param args* @returns {number}*/subtract(...args) {let calArr = this.getParam(args);let corrFactor = this.correctionFactor(calArr);let diff = calArr.reduce((accum, curr, curIndex) => {// reduce()函数在未传入初始值时,curIndex从1开始,第一位参与运算的值需要// 乘以最大乘数因子if (curIndex === 1) {return Math.round(accum * corrFactor) - Math.round(curr * corrFactor);}// accum作为上一次运算的结果,就无须再乘以最大因子return Math.round(accum) - Math.round(curr * corrFactor);});// 除以最大乘数因子return diff / corrFactor;},/*** 乘法运算* @param args* @returns {*}*/multiply(...args) {let calArr = this.getParam(args);let corrFactor = this.correctionFactor(calArr);calArr = calArr.map((item) => {// 乘以最大乘数因子return item * corrFactor;});let multi = calArr.reduce((accum, curr) => {return Math.round(accum) * Math.round(curr);}, 1);// 除以最大乘数因子return multi / Math.pow(corrFactor, calArr.length);},/*** 除法运算* @param 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;}
};
二、保留小数位为指定位数
在JavaScript中,toFixed函数有时也会导致一些四舍五入问题。这是因为JavaScript中的数字使用IEEE 754浮点数表示,存在精度有限的问题。
如:1.525.toFixed(2) 为1.52,而不是 1.53。
/*** 小数:四舍五入到指定位数* @param number 浮点数* @param decimalPlaces 需要保留的位数* @param isRemoveTrailingZeros {boolean} 是否去除尾部的0 // 如:3.00,为3* @returns {number}*/
export function roundToFixed(number, decimalPlaces = 2, isRemoveTrailingZeros = true) {const factor = 10 ** decimalPlaces; // **是幂运算符,左边是底数,右边是指数,即 2**3 = 8const result = Math.round(number * factor) / factor;if (isRemoveTrailingZeros) {return Number(result)} else { return result}
}