• 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
    
        }
    
  • 相关阅读:
    设计模式之工厂模式 练习
    c++智能指针(1)
    记录下 UTF6 GBK 转换函数
    ip白名单 通过* ? 检测IP匹配 轻量级
    stl学习记录(2)
    boost 学习(1)
    stl string 小练习
    stl string 使用指定的分隔符分割成数个子字符串
    [open source] skinbuilder发布
    Builder模式实例分析(C语言版)
  • 原文地址:https://www.cnblogs.com/gaozejie/p/14963452.html
Copyright © 2020-2023  润新知