我有以下虚拟测试脚本:

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

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

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

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


当前回答

我找不到使用内置的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 times = function (a, b) {
    return Math.round((a * b) * 100)/100;
};

---或---

var fpFix = function (n) {
    return Math.round(n * 100)/100;
};

fpFix(0.1*0.2); // -> 0.02

---此外---

var fpArithmetic = function (op, x, y) {
    var n = {
            '*': x * y,
            '-': x - y,
            '+': x + y,
            '/': x / y
        }[op];        

    return Math.round(n * 100)/100;
};

---如中所示---

fpArithmetic('*', 0.1, 0.2);
// 0.02

fpArithmetic('+', 0.1, 0.2);
// 0.3

fpArithmetic('-', 0.1, 0.2);
// -0.1

fpArithmetic('/', 0.2, 0.1);
// 2

你只是在做乘法吗?如果是这样的话,那么你可以利用一个关于十进制算术的简单秘密。即NumberOfDecimals(X)+NumberOfDecimals(Y)=预期的NumberOf小数。也就是说,如果我们有0.123*0.12,那么我们知道会有5位小数,因为0.123有3位小数,0.12有2位小数。因此,如果JavaScript给我们一个像0.014760000002这样的数字,我们可以安全地四舍五入到小数点后的第五位,而不用担心丢失精度。

您得到的结果是正确的,并且在不同语言、处理器和操作系统中的浮点实现之间相当一致——唯一改变的是当浮点实际上是双倍(或更高)时的不准确程度。

二进制浮点中的0.1与十进制中的1/3相似(即永远为0.333333333333333…),只是没有准确的方法来处理它。

如果您处理的是浮点数,那么总是会出现小的舍入误差,因此您也必须将显示的结果舍入到合理的值。作为回报,您可以得到非常快速和强大的算法,因为所有计算都是在处理器的本地二进制中进行的。

大多数情况下,解决方案不是切换到定点运算,主要是因为它速度慢得多,99%的时间你不需要精度。如果你处理的东西确实需要这样的准确性(例如金融交易),那么无论如何,Javascript可能不是最好的工具(因为你想要强制执行定点类型,静态语言可能更好)。

您正在寻找一个优雅的解决方案,但恐怕就是这样:浮点运算速度很快,但舍入误差很小-在显示结果时总是舍入到合理的值。

    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

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