JavaScript 中精度问题及简单解决办法
Sep 14, 2020 / 1 min read / 109
JavaScript 中的数字按照 IEEE 754 的标准,使用 64 位双精度浮点型来表示。其中符号位 S,指数位 E,尾数位M分别占了 1,11,52 位,并且在 ES5 规范 中指出了指数位E的取值范围是 [-1074, 971]。想用有限的位来表示无穷的数字,显然是不可能的,因此会出现一些列精度问题 比如 0.1 + 0.2 !== 0.3

解决思路一般是把浮点数转化为字符串,模拟实际运算的过程。

以下是 简单的 解决办法

// 两个浮点数求和
function fpAdd(num1, num2) {
    let r1, r2;
    try {
        r1 = num1.toString().split('.')[1].length;
    } catch (e) {
        r1 = 0;
    }
    try {
        r2 = num2.toString().split(".")[1].length;
    } catch (e) {
        r2 = 0;
    }
    const m = Math.pow(10, Math.max(r1, r2));
    return Math.round(num1 * m + num2 * m) / m;
}

// 两个浮点数相减
function fpSub(num1, num2) {
    var r1, r2
    try {
        r1 = num1.toString().split('.')[1].length;
    } catch (e) {
        r1 = 0;
    }
    try {
        r2 = num2.toString().split(".")[1].length;
    } catch (e) {
        r2 = 0;
    }
    const m = Math.pow(10, Math.max(r1, r2));
    const n = (r1 >= r2) ? r1 : r2;
    return (Math.round(num1 * m - num2 * m) / m).toFixed(n);
}
// 两个浮点数相除
function fpDiv(num1, num2) {
    var t1, t2
    try {
        t1 = num1.toString().split('.')[1].length;
    } catch (e) {
        t1 = 0;
    }
    try {
        t2 = num2.toString().split(".")[1].length;
    } catch (e) {
        t2 = 0;
    }
    const r1 = Number(num1.toString().replace(".", ""));
    const r2 = Number(num2.toString().replace(".", ""));
    return (r1 / r2) * Math.pow(10, t2 - t1);
}
// 两个浮点数相乘
function fpMul(num1, num2) {
    const m = 0, s1 = num1.toString(), s2 = num2.toString();
    try { m += s1.split(".")[1].length } catch (e) { };
    try { m += s2.split(".")[1].length } catch (e) { };
    return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
}