一七

  • 10
  • 文章数
  • 3
  • 分类数
  • 1
  • 评论数

一七

  • 10
  • 文章数
  • 3
  • 分类数
  • 1
  • 评论数

2023/06/14

「  关于JavaScript中的计算精度问题  」

众所周知使用JS进行运算时,偶尔会遇到计算精度不准确的问题,导致实际数值出现差异化,在某些涉及金额的场景这种问题更多的暴露在了用户面前,最近在项目中刚好遇到了在计算金额时精度出现差异化,故而记录一下。
首先JS的计算精度错误主要是因为JS采用的是浮点运算方式而不是整数运算方式,这就会导致精度错误,同时JS内部在计算除法算法时也会出现一些错误,因为JS无法精确的标识一些数字,比如:0.3
在JS中也有一些解决精度问题的方式,比如toFixed()方法,计算保留指定位数的小数,但是由于其计算时会四舍五入故而并不推荐使用,也可以使用toString()方法将数值改为字符串过后在进行运算,方法不止于此,更多的是根据业务场景判断,以下是我在开发中的实际情况。

以下是一个常见的金额补零函数,但是在运算转换时出现的计算精度错误

    /**
     * @param {number} value 
     * @param {number} count 
     * @returns string
     */
    keepDecimal(value, count = 2) {
        let f = parseFloat(value);
        if (isNaN(f)) {
            return "";
        }
        f = Math.floor(value * 100000) / 100000;
        let s = f.toString();
        let rs = s.indexOf(".");
        if (rs < 0) {
            rs = s.length;
            s += ".";
        }
        while (s.length <= rs + count) {
            s += "0";
        }
        return s.substring(0, rs + count + 1);
    }
    
    keepDecimal(8.075, 4)    // 期望获得 8.0750  结果  8.0749

通过对代码进行排查,发现是在 value * 100000 这一步出现的问题

    8.075 * 100000   The result is not the expected 807500 but 807499.999999...

    # 这就导致后续的补零转换都出现的错误...由于该tool函数所应用的模块较多,在不过多影响的情况下,选择扩大倍率来解决
    f = Math.floor(value * 100000) / 100000;  
    # 修改为
    f = Math.floor(value * 10000000) / 10000000;  // 问题解决!
总结: 在封装涉及JS运算的函数时,就应该考虑到计算精度问题,提前避免问题出现,尤其是设计金额等数值时

comments