聊一聊Javascript中的数字精度丢失问题
前言
在Javascript中,所有的数字都是以64位浮点数的形式存储的。这意味着Javascript可以表示的最大和最小的数字分别是2的1024次方和2的-1023次方。然而,这也意味着Javascript不能精确地表示一些十进制的小数,比如0.1
或0.2
。这可能会导致一些意想不到的结果,比如:
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 == 0.3); // false
为什么
在计算机中,所有的数字都是以二进制的形式来存储和处理的。而在二进制中,有些数是无法精确表示的,例如 0.1
就是一个无限循环小数,转换成二进制之后是 0.0001100110011001……
,因为计算机的存储精度是有限的,无法精确存储这样的数字,所以在进行小数运算时,可能会发生舍入误差,从而导致精度丢失。
而0.1
和0.2
在二进制中都是无限循环小数,所以在转换为64位浮点数时会有一定的舍入误差。这种误差在进行数学运算时会被放大,从而导致前言中的计算结果不准确。
解决方案
那么,如何解决这个问题呢?有几种常用的方法:
-
使用整数代替小数,比如把
0.1
变成1,把0.2
变成2,然后再除以10得到正确的结果。console.log((1 + 2) / 10); // 0.3
-
使用第三方的库,比如
Big.js
或Decimal.js
,它们可以提供任意精度的十进制运算。Big.js
安装方式
npm install big.js
使用方式
// 引入Big.js库 const Big = require('big.js'); // 使用Big.js进行任意精度的加法运算 const a = new Big('0.1'); const b = new Big('0.2'); const c = a.plus(b); console.log(c.toString()); // 输出 '0.3'
Decimal.js
安装方式
npm install decimal.js
使用方式
// 引入Decimal.js const Decimal = require('decimal.js'); // 创建Decimal对象 const a = new Decimal(0.1); const b = new Decimal('0.2'); // 进行计算 const c = a.plus(b); // 0.3 // 输出结果 console.log(c.toString()); // '0.3'
需要注意的是,在使用Decimal.js时,应该尽量避免使用JavaScript原生的数字类型,以免出现精度丢失的问题。
-
使用ES6中引入的
Number.EPSILON
,它表示最小的可以被表示的正数,可以用来判断两个浮点数是否相等。// 判断两个浮点数是否相等 function isEqual(num1, num2) { return Math.abs(num1 - num2) < Number.EPSILON; } console.log(isEqual(0.1 + 0.2, 0.3)); // 输出 true
总结
JavaScript中64位浮点数不能准确表示十进制小数,使用整数替代小数或Big.js
/Decimal.js
库执行任意精度运算,或使用Number.EPSILON
判断两个浮点数是否相同。
转载自:https://juejin.cn/post/7231374594815541305