目录
- ieee754标准
- 解决方法
和c语言一样,所有以ieee754标准的语言都有浮点数精度问题,js也有浮点数精度问题,并且因为是弱类型语言这个问题更严重,js的Number类型的数据都被视为浮点数
ieee754标准
js的数字类型就相当于c语言double类型,是64位的
- 符号位也是首位
- 指数位一共11位,表示指数
- 尾数位一共52位,表示小数点后的数,超出部分舍1进0
所以我们的小数表示只能是2**-1、2**-2、2**-3以此类推
也就是0.5,0.25,0.125
所以像0.1、0.7这些数据就无法精准表示,计算就会出错
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.7); // 0.7999999999999999
为了验证该例子,我们得先知道怎么将浮点数转换为二进制,整数我们可以用除 2 取余的方式,小数我们则可以用乘 2 取整的方式。
将0.1转为二进制
0.1 * 2,值为 0.2,小数部分 0.2,整数部分 0
0.2 * 2,值为 0.4,小数部分 0.4,整数部分 0
0.4 * 2,值为0.8,小数部分0.8,整数部分0
0.8 * 2,值为 1.6,小数部分 0.6,整数部分 1
0.6 * 2,值为 1.2,小数部分 0.2,整数部分 1
0.2 * 2,值为 0.4,小数部分 0.4,整数部分 0
从 0.2 开始循环,也就是0.00110011001100110…
而0.2的二进制为 0.00110011001100110011…
0.1 + 0.2 = 0.011011…
转为十进制
0.(02)-1+(12)-2+(1**2)-3…
最终在第52位截取(0舍1入)
所以 0.30000000000000004是这么来的
解决方法
通常这种对精度要求高的计算都应该交给后端去计算和存储,因为后端有成熟的库来解决这种计算问题。
前端也有几个不错的类库:
Math.js
Math.js 是专门为 JavaScript 和 Node.js 提供的一个广泛的数学库。它具有灵活的表达式解析器,支持符号计算,配有大量内置函数和常量,并提供集成解决方案来处理不同的数据类型。
像数字,大数字(超出安全数的数字),复数,分数,单位和矩阵。 功能强大,易于使用。
decimal.js
为 JavaScript 提供十进制类型的任意精度数值。
big.js
不仅能够支持处理 Long 类型的数据,也能够准确的处理小数的运算。