我有以下虚拟测试脚本:

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

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

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

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


当前回答

你是对的,原因是浮点数的精度有限。将有理数存储为两个整数的除法,在大多数情况下,您可以存储数字而不损失任何精度。在打印时,您可能希望将结果显示为分数。有了我提出的表示法,它就变得微不足道了。

当然,这对非理性数字没有太大帮助。但您可能希望优化您的计算,使其产生的问题最少(例如,检测sqrt(3)^2等情况)。

其他回答

注意,对于一般用途,这种行为可能是可以接受的。当比较这些浮点值以确定适当的操作时,会出现问题。随着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

我找不到使用内置的Number.EPSILON来解决这类问题的解决方案,因此我的解决方案如下:

function round(value, precision) {
  const power = Math.pow(10, precision)
  return Math.round((value*power)+(Number.EPSILON*power)) / power
}

这使用1和大于1的最小浮点数之间的已知最小差值来修正EPSILON舍入误差,结果仅比舍入阈值低一个EPSILON。

64位浮点的最大精度为15,32位浮点的最高精度为6。您的javascript可能是64位。

不优雅,但能完成任务(删除尾随零)

var num = 0.1*0.2;
alert(parseFloat(num.toFixed(10))); // shows 0.02

我发现BigNumber.js符合我的需求。

用于任意精度十进制和非十进制算术的JavaScript库。

它有很好的文档记录,作者对反馈非常认真。

同一作者还有其他两个类似的库:

Big.js

一个用于任意精度十进制运算的小型快速JavaScript库。bignumber.js的小妹妹。

和Decimal.js

JavaScript的任意精度Decimal类型。

下面是一些使用BigNumber的代码:

$(函数){var product=BigNumber(.1).times(.2);$('#product').text(product);var sum=BigNumber(.1).加号(.2);$('#sum').text(sum);});<script src=“https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js“></script><!-- 1.4.1不是当前版本,但适用于本示例。--><script src=“http://cdn.bootcss.com/bignumber.js/1.4.1/bignumber.min.js“></script>.1&次。2=<span id=“product”></span><br>.1加上。2=<span id=“sum”></span><br>

这对我有用:

function round_up( value, precision ) { 
    var pow = Math.pow ( 10, precision ); 
    return ( Math.ceil ( pow * value ) + Math.ceil ( pow * value - Math.ceil ( pow * value ) ) ) / pow; 
}

round_up(341.536, 2); // 341.54