行业知识
【JS】数值精度缺失问题解决方案
2026-11-03 07:04:48
来源:互联网转载
���法一:
()保留字符串类型,传给后端
方法二:
()如果涉及到计算,用以下方法
// 核心思想 在计算前,将数字乘以相同倍数,让他没有小数位,然后再进行计算,然后再除以相同的倍数,恢复原来的小数位function add(a, b) { const precisionA = getPrecisionA(a) const precisionB = getPrecisionB(b) var multiplier = Math.pow(10, Math.max(precisionA, precisionB)) return (a * multiplier + b * multiplier) / multiplier}function getPrecisionA() { if (num.toString().indexOf('e') !== -1) { var precision = num.toString().split('e-')[1] return parseInt(precision, 10) } var decimalPart = num.toString().split('.')[1] return decimalPart ? decimalPart.length : 0} 以下是完整函数:
/** * 把递归操作扁平迭代化 * @param {number[]} arr 要操作的数字数组 * @param {function} operation 迭代操作 * @private */function iteratorOperation(arr,operation){const [num1,num2,...others]=arr;let res=operation(num1,num2)other.forEach((num)=>{res=operation(res,num)})return res}/** * 返回小数部分的长度 * @private * @param {*number} num Input number */ function digitLength(num){ // 指数部分通常是用字母 "e" 或 "E" 后跟一个整数表示 const eSplit=num.toString().spilt(/[eE]/); const len=(eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0); return len>0?len:0;}/** * 把小数转成整数,如果是小数则放大成整数 * @private * @param {*number} num 输入数 */function float2Fixed(num){if(num.toString().indexOf('e')===-1){return Number(num.toString().replace('.',''))}const dLen = digitLength(num); return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);}/** * 把错误的数据转正 * @private * @example strip(0.09999999999999998)=0.1 */ function strip(num,precision=15){ // toPrecision将数字转换为具有指定有效数字位数的字符串表示形式 // parseFloat 将字符串转为浮点数 return +parseFloat(Number(num).toPrecision(precision)); }/** * 高精度乘法 */ function times(...nums){ if (nums.length > 2) { return iteratorOperation(nums, times); } const [num1, num2] = nums; const num1Changed = float2Fixed(num1); const num2Changed = float2Fixed(num2); const baseNum = digitLength(num1) + digitLength(num2); const leftValue=num1Changed * num2Changed // 并返回底数的指数次幂 return leftValue/ Math.pow(10, baseNum); }/** * 高精度加法 */ function plus(...nums){if(nums.length>2){return iteratorOperation(nums, plus)}const [num1,num2]=nums// 取最大的小数位// Math.pow 函数计算以 10 为底、指数为两个数字小数部分长度的最大值的幂次方const baseNum=Math.pow(10,Math.max(digitLength(num1), digitLength(num2)))// 把小数转为整数再计算 return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;}/** * 高精度减法 * @export */ function minus(...nums) { if (nums.length > 2) { return iteratorOperation(nums, minus); } const [num1, num2] = nums; const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2))); return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;}/** * 高精度除法 * @export */function pide(...nums) { if (nums.length > 2) { return iteratorOperation(nums, pide); } const [num1, num2] = nums; const num1Changed = float2Fixed(num1); const num2Changed = float2Fixed(num2); checkBoundary(num1Changed); checkBoundary(num2Changed); // 重要,这里必须用strip进行修正 return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));}