JS数字的精度损失
所有数字都是以 64 位浮点数形式储存,即便整数也是如此。 所以我们在打印 1.00
这样的浮点数的结果是 1
而非 1.00
任何一门语言都会存在数字的精度损失问题,计算机只识别二进制,用户输入十进制的数字之后,计算机会将其转化成二进制进行运算,在转化成10进制返回给用户,在这些转化中可能会存在一些误差,
这里有一些经典的例子
0.1 + 0.2
运算结果:0.30000000000000004
// 0.7 + 0.1 = 0.7999999999999999
// 0.2 + 0.4 = 0.6000000000000001
// 2.22 + 0.1 = 2.3200000000000003
不论是在浏览器中,java或者是python中都会输出0.30000000000000004
9999999999999999 == 10000000000000001
true
16位的数字与17位相等
1.335.toFixed(2) // 1.33 四舍五入失效
计算机的二进制实现和位数限制有些数无法有限表示 就像一些无理数不能有限表示,如 圆周率 3.1415926…,1.3333… 等
精度损失的根本原因
浮点数四舍五入,模仿十进制进行四舍五入,由于二进制只有 0 和 1 两个,于是变为 0 舍 1 入。这即是计算机中部分浮点数运算时出现误差,丢失精度的根本原因。
大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),转化成10进制十进制即 9007199254740992,大于 9007199254740992 的可能会丢失精度
pow() 方法可返回 x 的 y 次幂的值。
看似有穷的数字, 在计算机的二进制表示里却是无穷的,由于存储位数限制因此存在“舍去”,精度丢失就发生了。
避免
对于整数,前端出现问题的几率可能比较低,毕竟很少有业务需要需要用到超大整数,只要运算结果不超过 Math.pow(2, 53) 就不会丢失精度。
对于小数,前端出现问题的几率还是很多的,尤其在一些电商网站涉及到金额等数据。解决方式:把小数放到位整数(乘倍数),再缩小回原来倍数(除倍数)
(0.1*100 + 0.2 *100)/100;
+ 引入Math.js
Math.js 是专门为 JavaScript 和 Node.js 提供的一个广泛的数学库。它具有灵活的表达式解析器,支持符号计算,配有大量内置函数和常量,并提供集成解决方案来处理不同的数据类型 像数字,大数字(超出安全数的数字),复数,分数,单位和矩阵。
+ 转化成字符串
对于整数,我们可以通过用String
类型的表示来取值或传值,否则会丧失精度。
+ 浮点数运算
在判断浮点数运算结果前对计算结果进行精度缩小,因为在精度缩小的过程总会自动四舍五入。
toFixed() 方法使用定点表示法来格式化一个数,会对结果进行四舍五入。