我有以下虚拟测试脚本:

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

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

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

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


当前回答

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

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

其他回答

你只需要决定你实际想要多少个小数位数-不能既吃蛋糕又吃蛋糕:-)

随着每一次进一步的操作,数值误差都会累积,如果你不及早切断它,它只会增长。数值库显示的结果看起来很干净,只需在每一步中删除最后2位数字,数值协处理器也有“正常”和“完整”长度,原因相同。对于一个处理器来说,截断是便宜的,但对于脚本(乘法、除法和使用pov(…))来说非常昂贵。好的数学库将提供floor(x,n)来为您进行截断。

因此,至少您应该使用pov(10,n)使全局var/常量-这意味着您决定了所需的精度:-)然后执行:

Math.floor(x*PREC_LIM)/PREC_LIM  // floor - you are cutting off, not rounding

你也可以继续做数学运算,只在最后截止——假设你只显示结果而不做if-s。如果你能做到这一点,那么.toFixed(…)可能会更有效率。

如果您正在进行If-s/比较,并且不想截断,那么还需要一个小常数,通常称为eps,它比最大预期误差高一个小数位。假设你的截止值是最后两位小数,那么你的eps在倒数第三位(第三位最不重要)有1,你可以用它来比较结果是否在预期的eps范围内(0.02-eps<0.1*0.2<0.02+eps)。

为了避免这种情况,您应该使用整数值而不是浮点。因此,当您希望使用值*100进行2个位置的精度工作时,对于3个位置使用1000。显示时,使用格式化程序放入分隔符。

许多系统省略了以这种方式处理小数。这就是为什么许多系统使用美分(作为整数)而不是美元/欧元(作为浮点)的原因。

使用以下功能输出:

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)的输出。

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

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

这个npm库是为了从我自己的用例中解决这个问题而构建的,并且已经在大规模生产中部署。希望对其他人有所帮助。

npm i jsbi计算器

它基于GoogleChromeLabs/jsbi项目,使用字符串化表达式执行任意有理计算,兼容ie11。

浏览器的用法:

<!DOCTYPE html><html lang=“en”><head><meta charset=“UTF-8”/><meta http equiv=“X-UA-Compatible”content=“IE=edge”/><meta name=“viewport”content=“width=设备宽度,初始比例=1.0”/><title>Jsbi计算器测试</title><script src=“https://cdn.jsdelivr.net/npm/jsbi-calculator/dist/jsbi-calculator-umd.js“></script></head><body></body><script type=“text/javascript”>常量表达式One=“((10*(24/((9+3)*(-2))))+17)+5.2”;const resultOne=JBC.calculator(expressionOne);console.log(resultOne);// -> '12.2'const userAgent=navigator.userAgent;常量为IE11=userAgent.indexOf(“Trident”)>-1&&userAgent.inindexOf(”rv:11.0“)>-1;let max;//MAX_SAFE_INTEGER在IE11中不可用max=isIE11?“9007199254740991”:字符串(编号.MAX_SAFE_INTEGER);console.log(最大值);// -> '9007199254740991'常量表达式Two=max+“+2.2”;const resultTwo=JBC.calculator(表达式Two);console.log(resultTwo);// -> '9007199254740993.2'</script></html>