js处理浮点数计算误差(精确度)

js处理浮点数计算误差
众所周知, 浮点计算会产生舍入误差的问题, 比如, 0.1 + 0.2, 结果应该是0 .3, 但是计算的结果并不是如此, 而是0 .30000000000000004

我们知道,能被计算机读懂的是二进制,而不是十进制,所以我们先把 0.1 和 0.2 转换成二进制:
0.1==》0.1.toString(2)==》0.0001100110011(无限循环..)
0.2==》0.2.toString(2)==》0.001100110011 (无限循环..)

双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

网上流行一种写法:
就是先乘以一个倍数,将其变为整数,再相加,再除以倍数的方法,这个方法乍一看,是行的通的,但是经过测试,此方法也会存在bug。

下面是改良后直接上代码

 function accAdd(arg1, arg2) {
        var r1, r2, m, c;
        try {
            r1 = arg1.toString().split(".")[1].length;
            console.log(arg1.toString().split("."))
        } catch (e) {
            r1 = 0;
        }
        try {
            r2 = arg2.toString().split(".")[1].length;
        } catch (e) {
            r2 = 0;
        }
        c = Math.abs(r1 - r2); //位数差的绝对值
        m = Math.pow(10, Math.max(r1, r2)); //较大数的幂
        if (c > 0) { //位数相差
            var cm = Math.pow(10, c);
            if (r1 > r2) {     
                arg1 = Number(arg1.toString().replace(".", "")); //转化成数字
                arg2 = Number(arg2.toString().replace(".", "")) * cm;
            } else {
                arg1 = Number(arg1.toString().replace(".", "")) * cm;
                arg2 = Number(arg2.toString().replace(".", ""));
            }
        } else { //位数相等
            arg1 = Number(arg1.toString().replace(".", ""));
            arg2 = Number(arg2.toString().replace(".", ""));
        }
        console.log(arg1 + arg2, arg1, arg2)
        return (arg1 + arg2) / m;
    }


        let a = accAdd(0.1, 0.7); 
        console.log(a, 0.1 + 0.7) //0.8 0.7999999999999999

与第一种方法不同的是 不是每一个加数都乘以倍数,而是比较加数小数点后的位数,位数大的转为字符串,然后用空替换掉小数点再转为number类型,小数点后位数小的去乘以乘以倍数,两者相加再除以倍数就可以得到准确值;
其他 减 乘除 类似

摘自https://www.cnblogs.com/yky-iris/p/10083097.html

你可能感兴趣的:(js处理浮点数计算误差(精确度))