「这是我参与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.1 和 0.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
浮点数转化成整数
既然浮点数不准确,我们可以把它转为整数计算。可以将浮点数乘以 10 的 n 次方(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.
结语
如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。
文章如有错误之处,希望在评论区指正🙏🙏