我有以下虚拟测试脚本:

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

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

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

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


当前回答

我通常用这样的东西。

function pf(n) {
    return Math.round(n * 1e15) / 1e15;
}

我并不认为这在任何方面都是最佳的,但我喜欢它的简单性。它将数字四舍五入到小数点后15位左右。我没有看到它返回不准确的浮点数,但奇怪的是,当我在末尾使用*1e-15时,它已经这样做了,但没有使用这种方法。

这种解决方案可能更适合于随意使用,而不是精确的数学使用,因为精确错误会扰乱代码。

其他回答

我喜欢佩德罗·拉达里亚的解决方案,并使用类似的方法。

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

与Pedros解决方案不同,这将向上取整0.999……重复,并精确到最低有效位数的正负一。

注意:当处理32位或64位浮点时,应该使用toPrecision(7)和toPrecision(15)以获得最佳结果。有关原因的信息,请参阅此问题。

我在MOD3中遇到了一个严重的舍入错误问题。有时当我应该得到0时,我会得到.000…01。这很容易处理,只需测试<=0.01即可。但有时我会得到2.99999999999998。哎哟!

BigNumbers解决了这个问题,但引入了另一个有点讽刺的问题。当试图将8.5加载到BigNumbers时,我被告知它真的是8.4999…并且有超过15个有效数字。这意味着BigNumbers无法接受它(我认为我提到这个问题有点讽刺)。

讽刺问题的简单解决方案:

x = Math.round(x*100);
// I only need 2 decimal places, if i needed 3 I would use 1,000, etc.
x = x / 100;
xB = new BigNumber(x);

如果需要进行任意精度浮点计算,可以使用我的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>

根据@SheetJs的回答,将其组合在一起,我很喜欢:

getCorrection Factor(numberToCheck:number):数字{var correction Factor:数量=1;if(!Number.isInteger(numberToCheck)){while(!Number.isInteger(numberToCheck)){校正系数*=10;numberToCheck*=校正系数;}}回归修正因子;}

我有一个变通办法。例如,仅与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);
    }       
}

可怕但有效:)