我有以下虚拟测试脚本:

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

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

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

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


当前回答

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

其他回答

如果需要进行任意精度浮点计算,可以使用我的NPM库gmp-wasm,它基于gmp+MPFR库。您可以轻松设置所需的任何精度,并以固定精度返回结果。

<script src=“https://cdn.jsdelivr.net/npm/gmp-wasm“></script><脚本>gmp.init().then(({getContext})=>{const ctx=getContext({precisionBits:100});常量结果=ctx.Float('0.1').mul(ctx.Flat('0.2'));document.write(`0.1*0.2=`+result.toFixed(2));ctx.destroy();});</script>

问题

浮点不能精确存储所有十进制值。因此,当使用浮点格式时,输入值将始终存在舍入错误。输入端的错误当然会导致输出端的错误。在离散函数或运算符的情况下,函数或运算符离散的点附近的输出可能存在很大差异。

浮点值的输入和输出

因此,在使用浮点变量时,您应该始终注意这一点。并且,在显示之前,无论您希望从带有浮点的计算中获得什么输出,都应该在显示之前进行格式化/调整。当只使用连续函数和运算符时,舍入到所需的精度通常是可行的(不要截断)。用于将浮点数转换为字符串的标准格式功能通常会为您提供这一功能。由于舍入增加了一个误差,该误差可能导致总误差超过所需精度的一半,因此应根据输入的预期精度和输出的预期精度对输出进行校正。你应该

将输入舍入到预期精度,或确保不能输入精度更高的值。在舍入/格式化输出之前,为输出添加一个小值,该值小于或等于所需精度的1/4,并且大于输入和计算期间舍入误差导致的最大预期误差。如果不可能,则所用数据类型的精度组合不足以为计算提供所需的输出精度。

这两件事通常都没有做,在大多数情况下,不做它们所造成的差异太小,对大多数用户来说都不重要,但我已经有了一个项目,如果没有这些更正,输出不会被用户接受。

离散函数或运算符(如模)

当涉及离散运算符或函数时,可能需要额外的校正以确保输出符合预期。舍入和在舍入之前添加小的修正并不能解决这个问题。应用离散函数或运算符后,可能需要立即对中间计算结果进行特殊检查/校正。对于特定的情况(模运算符),请参阅我对问题的回答:为什么模运算符在javascript中返回小数?

最好避免出现问题

通过使用数据类型(整数或定点格式)进行这样的计算,通常可以更有效地避免这些问题,这样可以存储预期的输入,而不会出现舍入误差。这方面的一个例子是,您永远不应该在财务计算中使用浮点值。

Use

var x = 0.1*0.2;
 x =Math.round(x*Math.pow(10,2))/Math.pow(10,2);

    You can use library https://github.com/MikeMcl/decimal.js/. 
    it will   help  lot to give proper solution. 
    javascript console output 95 *722228.630 /100 = 686117.1984999999
    decimal library implementation 
    var firstNumber = new Decimal(95);
    var secondNumber = new Decimal(722228.630);
    var thirdNumber = new Decimal(100);
    var partialOutput = firstNumber.times(secondNumber);
    console.log(partialOutput);
    var output = new Decimal(partialOutput).div(thirdNumber);
    alert(output.valueOf());
    console.log(output.valueOf())== 686117.1985

我有一个变通办法。例如,仅与10E^x相乘不适用于1.1。

function sum(a,b){
    var tabA = (a + "").split(".");
    var tabB = (b + "").split(".");
    decA = tabA.length>1?tabA[1].length:0;
    decB = tabB.length>1?tabB[1].length:0;
    a = (tabA[0]+tabA[1])*1.0;
    b = (tabB[0]+tabB[1])*1.0;
    var diff = decA-decB;
    if(diff >0){
        //a has more decimals than b
        b=b*Math.pow(10,diff);
        return (a+b)/Math.pow(10,decA);
    }else if (diff<0){
        //a has more decimals than b
        a=a*Math.pow(10,-diff);
                return (a+b)/Math.pow(10,decB);
    }else{
        return (a+b)/Math.pow(10,decA);
    }       
}

可怕但有效:)