JS浮点数计算误差解释及解决方案

1 概述

浮点数指的是带有小数的数值,浮点运算即是小数的四则运算,常用来测量电脑运算速度。大部份计算机采用二進制(b=2)的表示方法。位(bit)是衡量浮点数所需存储空间的单位,通常为32位或64位,分别被叫作单精度和双精度。

2 误差现象

console.log(0.1+0.2);    // 输出 0.30000000000000004
console.log(0.15+0.15);  // 输出 0.3
 
console.log(0.7+0.1);    // 输出 0.7999999999999999
console.log(0.6+0.2);    // 输出 0.8
 
console.log(0.3*3);      // 输出 0.8999999999999999
console.log(3*3/10);     // 输出 0.9

从以上现象可以看出,并不是所有的浮点数运算都会出问题,只是部分。

0.7+0.1 输出有偏差

0.6+0.2 输出正确

具体是什么原因呢,继续向下看。

3 误差原因

不仅仅是JS,大多数语言在处理浮点数的时候都会遇到精度问题,准确的说,所有支持二进制浮点数运算(绝大部分都是 IEEE 754 的实现)的系统都存在这个现象。
其原因就是,在有限的存储空间下,绝大部分的十进制小数都不能用二进制浮点数来精确表示。例如,0.1 这个简单的十进制小数就不能用二进制浮点数来表示。所谓「计算机浮点数」,其实就是二进制的「科学计数法」。在十进制中,科学计数法的形式是:
在这里插入图片描述
相应的,二进制的科学计数法就是:
在这里插入图片描述
而在有限的存储空间下,十进制小数 0.1 无论如何也不能用这种形式来表示,因此,计算机在存储它时,产生了精度丢失,所以就出现了问题中所描述的现象。
更详细的可以点击链接查看 https://www.zhihu.com/question/20679634

4 解决方案

如何解决呢?看这个例子:

console.log(0.3*3);      // 输出 0.8999999999999999
console.log(3*3/10);     // 输出 0.9

浮点数计算有问题,整数计算是没问题的,那么将浮点转化成整数运算,之后再切回浮点就可以保证没有偏差了

注:不推荐js做太多的浮点运算。

以下方法可以帮助你修正浮点运算的偏差:

// 浮点数求和
function add(a, b) {
    
    
    var c, d, e;
    try {
    
    
        c = a.toString().split(".")[1].length;
    } catch (f) {
    
    
        c = 0;
    }
    try {
    
    
        d = b.toString().split(".")[1].length;
    } catch (f) {
    
    
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
}
 
// 浮点数相减
function sub(a, b) {
    
    
    var c, d, e;
    try {
    
    
        c = a.toString().split(".")[1].length;
    } catch (f) {
    
    
        c = 0;
    }
    try {
    
    
        d = b.toString().split(".")[1].length;
    } catch (f) {
    
    
        d = 0;
    }
    return e = Math.pow(10, Math.max(c, d)), (mul(a, e) - mul(b, e)) / e;
}
 
// 浮点数相乘
function mul(a, b) {
    
    
    var c = 0,
        d = a.toString(),
        e = b.toString();
    try {
    
    
        c += d.split(".")[1].length;
    } catch (f) {
    
    }
    try {
    
    
        c += e.split(".")[1].length;
    } catch (f) {
    
    }
    return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}
 
// 浮点数相除
function div(a, b) {
    
    
    var c, d, e = 0,
        f = 0;
    try {
    
    
        e = a.toString().split(".")[1].length;
    } catch (g) {
    
    }
    try {
    
    
        f = b.toString().split(".")[1].length;
    } catch (g) {
    
    }
    return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), mul(c / d, Math.pow(10, f - e));
}

验证

console.log(0.1+0.2);        // 输出 0.30000000000000004
console.log(add(0.1, 0.2));  // 输出 0.3
 
console.log(0.7+0.1);        // 输出 0.7999999999999999
console.log(add(0.7, 0.1));  // 输出 0.8
 
console.log(0.3*3);          // 输出 0.8999999999999999
console.log(mul(0.3, 3));    // 输出 0.9

博文部分来自知乎和其它博客,感谢!

猜你喜欢

转载自blog.csdn.net/qq_41800366/article/details/102754335