如何处理JavaScript中的浮点数精度?

我有以下虚拟测试脚本:

function test(){
    var x = 0.1 * 0.2;
    document.write(x);
}
test();

这将打印结果0.020000000000000004而它应该只打印0.02 (如果你使用你的计算器)。 据我了解这是由于浮点乘法精度的错误。

有没有人有一个好的解决方案,以便在这种情况下,我得到0.02的正确结果? 我知道有功能,如toFixed或倒圆会是另一种可能性,但我真的希望有印无任何切割和四舍五入的整数。 只是想知道你们中的一个是否有一些漂亮,优雅的解决方案。

当然,否则我会轮到10个左右的数字。


从浮点指南:

我能做些什么来避免这个问题?

这取决于你在做什么样的计算。

  • 如果你真的需要你的结果加起来,特别是当你使用金钱时:使用特殊的十进制数据类型。
  • 如果您不想看到所有这些额外的小数位:只需在显示时将结果格式化为固定的小数位数。
  • 如果你没有可用的小数数据类型,另一种方法是使用整数,例如完全以美分计算。 但是这是更多的工作,并有一些缺点。
  • 请注意,第一点仅适用于您确实需要特定的精确小数行为。 大多数人并不需要这些,他们只是激怒了他们的程序不能像1/10这样的数字正常工作,却没有意识到如果发生1/3的话,他们甚至不会眨眼同样的错误。

    如果第一点确实适用于您,请使用BigDecimal for JavaScript,它根本不算优雅,但实际上解决了问题,而不是提供不完善的解决方法。


    我喜欢Pedro Ladaria的解决方案并使用类似的东西。

    function strip(number) {
        return (parseFloat(number).toPrecision(12));
    }
    

    与Pedros解决方案不同,这将收集0.999 ...重复,并且精确到最低有效位数的正负1。

    注意:处理32或64位浮点数时,应使用toPrecision(7)和toPrecision(15)以获得最佳结果。 看到这个问题的原因信息。


    对于数学上的倾向:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

    推荐的方法是使用校正因子(乘以10的适当幂使得算术在整数之间发生)。 例如,在0.1 * 0.2的情况下,校正因子是10 ,并且您正在执行计算:

    > var x = 0.1
    > var y = 0.2
    > var cf = 10
    > x * y
    0.020000000000000004
    > (x * cf) * (y * cf) / (cf * cf)
    0.02
    

    (非常快)解决方案看起来像这样:

    var _cf = (function() {
      function _shift(x) {
        var parts = x.toString().split('.');
        return (parts.length < 2) ? 1 : Math.pow(10, parts[1].length);
      }
      return function() { 
        return Array.prototype.reduce.call(arguments, function (prev, next) { return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); }, -Infinity);
      };
    })();
    
    Math.a = function () {
      var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
      function cb(x, y, i, o) { return x + f * y; }
      return Array.prototype.reduce.call(arguments, cb, 0) / f;
    };
    
    Math.s = function (l,r) { var f = _cf(l,r); return (l * f - r * f) / f; };
    
    Math.m = function () {
      var f = _cf.apply(null, arguments);
      function cb(x, y, i, o) { return (x*f) * (y*f) / (f * f); }
      return Array.prototype.reduce.call(arguments, cb, 1);
    };
    
    Math.d = function (l,r) { var f = _cf(l,r); return (l * f) / (r * f); };
    

    在这种情况下:

    > Math.m(0.1, 0.2)
    0.02
    

    我绝对推荐使用像SinfulJS这样的测试过的库

    链接地址: http://www.djcxy.com/p/4713.html

    上一篇: How to deal with floating point number precision in JavaScript?

    下一篇: What is the best way to compare floats for almost