JS加减乘除精度丢失问题解决

一、前言

​ 工作中经常遇到用户输入后在前端实时计算结果,比如输入单价和数量后自动计算总价,部分情况下会出现丢失精度的问题。解决方式为将小数放大为整数,计算完后再缩小。

二、解决

   /*
    * 加法
    * add(0.123 , 1.4567 , 10.56789)
    */
    function add(...val) {
      let sum = 0,
        maxDecimalLength = getMaxDecimalLength(...val)

      val.forEach((x, index) => {
        // 所有数值转为整数计算
        sum += Math.round(x * Math.pow(10, maxDecimalLength))
      })

      return sum / Math.pow(10, maxDecimalLength)
    }

    /*
    * 减法
    * subtract(0.123 , 1.4567 , 10.56789)
    */
    function subtract(...val) {
      let sum,
        maxDecimalLength = getMaxDecimalLength(...val)

      val.forEach((x, index) => {
        let nurVal = Math.round(x * Math.pow(10, maxDecimalLength));

        if (index === 0)
          sum = nurVal
        else
          sum -= nurVal
      })

      return sum / Math.pow(10, maxDecimalLength)
    }

    /*
    * 乘法
    * multiply(0.123 , 1.4567 , 10.56789)
    */
    function multiply(...val) {
      let sum,
        decimalLengthSum = 0

      val.forEach((x, index) => {
        // 获取当前小数位长度
        let decimalLength = getMaxDecimalLength(x)
        // 将当前数变为整数
        let nurVal = Math.round(x * Math.pow(10, decimalLength));

        decimalLengthSum += decimalLength

        if (index === 0)
          sum = nurVal
        else
          sum *= nurVal
      })

      return sum / Math.pow(10, decimalLengthSum)

    }

    /*
    * 除法
    * divide(0.123 , 1.4567 , 10.56789)
    */
    function divide(...val) {

      let sum = 0,
        decimalLengthSum = 0

      val.forEach((x, index) => {
        // 获取当前小数位长度
        let decimalLength = getMaxDecimalLength(x)
        // 将当前数变为整数
        let nurVal = Math.round(x * Math.pow(10, decimalLength));

        if (index === 0) {
          decimalLengthSum = decimalLength

          sum = nurVal
        } else {
          decimalLengthSum -= decimalLength
          sum /= nurVal
        }
      })

      return sum / Math.pow(10, decimalLengthSum)

    }

    /*
    * 获取小数位数
    */
    function getMaxDecimalLength(...val) {
      // 最大小数位长度
      let maxDecimalLength = 0

      val.forEach((x) => {

        const strVal = x.toString(),
          dotIndex = strVal.indexOf('.')
        if (dotIndex > -1) {
          // 获取当前值小数位长度
          let curDecimalLength = strVal.length - 1 - dotIndex

          if (curDecimalLength > maxDecimalLength) {
            maxDecimalLength = curDecimalLength
          }
        }
      })

      return maxDecimalLength

    }
posted @ 2021-07-02 15:24  gaozejie  阅读(1144)  评论(0编辑  收藏  举报