我有以下虚拟测试脚本:

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

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

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

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


当前回答

我发现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>

其他回答

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

看看固定点算法。如果你想操作的数字范围很小(例如货币),它可能会解决你的问题。我会将其舍入为几个十进制值,这是最简单的解决方案。

当添加两个浮点值时,它永远不会给出精确的值,因此我们需要将其固定为有助于我们进行比较的某个数字。

console.log((parseFloat(0.1)+parseFlat(0.2)).toFixed(1)==parseFloat(0.3).toFixed(1));

首先将两个数字都设为整数,执行表达式,然后对结果进行除法运算,以返回小数点:

function evalMathematicalExpression(a, b, op) {
    const smallest = String(a < b ? a : b);
    const factor = smallest.length - smallest.indexOf('.');

    for (let i = 0; i < factor; i++) {
        b *= 10;
        a *= 10;
    }

    a = Math.round(a);
    b = Math.round(b);
    const m = 10 ** factor;
    switch (op) {
        case '+':
            return (a + b) / m;
        case '-':
            return (a - b) / m;
        case '*':
            return (a * b) / (m ** 2);
        case '/':
            return a / b;
    }

    throw `Unknown operator ${op}`;
}

几个操作的结果(排除的数字是eval的结果):

0.1 + 0.002   = 0.102 (0.10200000000000001)
53 + 1000     = 1053 (1053)
0.1 - 0.3     = -0.2 (-0.19999999999999998)
53 - -1000    = 1053 (1053)
0.3 * 0.0003  = 0.00009 (0.00008999999999999999)
100 * 25      = 2500 (2500)
0.9 / 0.03    = 30 (30.000000000000004)
100 / 50      = 2 (2)

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