我有以下虚拟测试脚本:

函数测试(){变量x=0.1*0.2;document.write(x);}测试();

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

有没有人有一个好的解决方案,在这种情况下,我得到了正确的结果0.02?我知道还有一些函数,比如toFixed或舍入,这是另一种可能,但我真的希望在不进行任何切割和舍入的情况下打印整个数字。我只是想知道你们中的一个人是否有一些好的、优雅的解决方案。

当然,否则我会舍入到10位数左右。


当前回答

注意,对于一般用途,这种行为可能是可以接受的。当比较这些浮点值以确定适当的操作时,会出现问题。随着ES6的出现,定义了一个新的常数Number.EPSILON来确定可接受的误差容限:所以不要像这样进行比较

0.1 + 0.2 === 0.3 // which returns false

您可以定义自定义比较函数,如下所示:

function epsEqu(x, y) {
    return Math.abs(x - y) < Number.EPSILON;
}
console.log(epsEqu(0.1+0.2, 0.3)); // true

资料来源:http://2ality.com/2015/04/numbers-math-es6.html#numberepsilon

其他回答

您不能用二进制浮点类型(这是ECMAScript用来表示浮点值的)精确地表示大多数小数。因此,除非您使用任意精度的算术类型或基于小数的浮点类型,否则没有一个优雅的解决方案。例如,Windows附带的计算器应用程序现在使用任意精度算法来解决这个问题。

要处理任意浮点数,请执行以下操作:

function shorten(num) {
    num += 0.000000001;// to deal with "12.03999999997" form
    num += '';
    return num.replace(/(\.\d*?)0{5,}\d+$/, '$1') * 1;
}

console.log(1.2+1.9===1.3+1.8);// false
console.log(shorten(1.2+1.9)===shorten(1.3+1.8));// true

您正在寻找JavaScript的sprintf实现,这样您就可以以期望的格式写出带有小错误的浮点数(因为它们是以二进制格式存储的)。

试试javascript sprintf,你可以这样称呼它:

var yourString = sprintf("%.2f", yourNumber);

将数字打印为带有两个小数点的浮点数。

如果您不希望仅为浮点舍入到给定精度而包含更多文件,也可以使用Number.toFixed()进行显示。

使用以下功能输出:

var toFixedCurrency = function(num){
    var num = (num).toString();
    var one = new RegExp(/\.\d{1}$/).test(num);
    var two = new RegExp(/\.\d{2,}/).test(num);
    var result = null;

    if(one){ result = num.replace(/\.(\d{1})$/, '.$10');
    } else if(two){ result = num.replace(/\.(\d{2})\d*/, '.$1');
    } else { result = num*100; }

    return result;
}

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

test();

注意FixedCurrency(x)的输出。

试试我的千年算术库,你可以在这里看到。如果你想要更高版本,我可以给你买一个。