精确加减乘除

/**
 * 解决 js 浮点运算时精度丢失问题
 * plus 加
 * minus 减
 * times 乘
 * divide 除
 */

/**
 * 把错误的数据转正
 * strip(0.09999999999999998)=0.1
 */
function strip(num, precision = 12) {
  return +parseFloat(num.toPrecision(precision))
}

/**
 * Return digits length of a number
 * @param {*number} num Input number
 */
function digitLength(num) {
  // Get digit length of e
  const eSplit = num.toString().split(/[eE]/)
  const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0)
  return len > 0 ? len : 0
}

/**
 * 把小数转成整数,支持科学计数法。如果是小数则放大成整数
 * @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(num * Math.pow(10, dLen)) : num
}

/**
 * 精确加法
 */
Math.plus = function (num1, num2, ...others) {
  if (others.length > 0) {
    return Math.plus(Math.plus(num1, num2), others[0], ...others.slice(1))
  }
  const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)))
  return (Math.times(num1, baseNum) + Math.times(num2, baseNum)) / baseNum
}

/**
 * 精确减法
 */
Math.minus = function (num1, num2, ...others) {
  if (others.length > 0) {
    return Math.minus(Math.minus(num1, num2), others[0], ...others.slice(1))
  }
  const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)))
  return (Math.times(num1, baseNum) - Math.times(num2, baseNum)) / baseNum
}

/**
 * 精确乘法
 */
Math.times = function (num1, num2, ...others) {
  if (others.length > 0) {
    return Math.times(Math.times(num1, num2), others[0], ...others.slice(1))
  }
  const num1Changed = float2Fixed(num1)
  const num2Changed = float2Fixed(num2)
  const baseNum = digitLength(num1) + digitLength(num2)
  const leftValue = num1Changed * num2Changed

  return leftValue / Math.pow(10, baseNum)
}

/**
 * 精确除法
 */
Math.divide = function (num1, num2, ...others) {
  if (others.length > 0) {
    return Math.divide(Math.divide(num1, num2), others[0], ...others.slice(1))
  }
  const num1Changed = float2Fixed(num1)
  const num2Changed = float2Fixed(num2)
  return Math.times(num1Changed / num2Changed, Math.pow(10, digitLength(num2) - digitLength(num1)))
}
posted @ 2025-09-12 10:55  小菜波  阅读(9)  评论(0)    收藏  举报