0.1 + 0.2 !== 0.3🤔🤔

449 阅读2分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

问题思考

在浏览器中执行下面的情况,看下它们的执行结果:

1. 0.2 - 0.1  // 0.1

2. 1.1+0.2 // 1.3

3. 0.2+0.2-0.3  // 0.10000000000000003

4. 0.1 + 0.2 // 0.30000000000000004

如果按照我们正常的计算法则,上面第3 和 第4 不应该是 0.10.3 吗,然而事实并非如此,计算不是人脑,它只是一个无情的机器,不能直接使用人的思维方式去计算。那么到底是什么原因导致的这个结果呢?

原因

js数字采用的IEEE 754双精度标准进行存储(存储一个数值所使用的二进制位数比较多, 精度更准确)。

对于像 0.1 这样的数值用二进制表示你就会发现无法整除,最后算下来会是0.0001100110011001...由于存储空间有限,位数是无限的,只能取近似。

什么是 IEEE 754

IEEE 二进制浮点数算术标准IEEE 754)是20世纪80年代以来最广泛使用的浮点数运算标准,为许多CPU浮点运算器所采用。

IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)双精确度(64位)延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)

多余的就不再赘述了,具体参考

如何解决呢?

es6 解决办法

es6 提供了 Number.EPSILON,这个值等于 2^-52 ,这个值非常非常小,在底层计算机已经帮我们运算好,并且无限接近 0,但不等于 0,这个时候我们只要判断误差值在这个范围内就可以说明是相等的。

function numbersequal(a,b){
    return Math.abs(a-b)<Number.EPSILON
}
const a = 0.1 + 0.2;
const b = 0.3;
console.log(numbersequal(a, b))
// true

浮点数转化成整数

既然浮点数不准确,我们可以把它转为整数计算。可以将浮点数乘以 10n 次方(n>0).

(0.1 * 10 + 0.2 * 10) / 10
// 0.3

四舍五入

采用四舍五入方法,取了一个 10 位小数

function numTofixed(num) {
    if (typeof num == 'number') {
        num = parseFloat(num.toFixed(10))
    }
    return num;
}

numTofixed(0.1 + 0.2);
// 0.3

使用第三方库

这里推荐一个 「bignumber

A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic.

结语

如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。

文章如有错误之处,希望在评论区指正🙏🙏