js数字位数太⼤导致参数精度丢失问题
最近遇到个⽐较奇怪的问题,js函数⾥传参,传⼀个位数⽐较⼤,打印arguments可以看到传过来的参数已经改变。
然后查了⼀下,发现确实是js精度丢失造成的。我的解决⽅法是将数字型改成字符型传输,这样就不会造成精度丢失了。如下图:
JS 数字丢失精度的原因
计算机的⼆进制实现和位数限制有些数⽆法有限表⽰。就像⼀些⽆理数不能有限表⽰,如圆周率 , 等。JS 遵循规范,采⽤双精度存储(double precision),占⽤ 64 bit。如图
意义
1位⽤来表⽰符号位
11位⽤来表⽰指数
52位表⽰尾数
浮点数,⽐如
1 20.1 >> 0.0001 1001 1001 1001…(1001⽆限循环)0.
2 >> 0.0011 0011 0011 0011…(0011⽆限循环)
此时只能模仿⼗进制进⾏四舍五⼊了,但是⼆进制只有 0 和 1 两个,于是变为 0 舍 1 ⼊。这即是计算机中部分浮点数运算时出现误差,丢失精度的根本原因。
⼤整数的精度丢失和浮点数本质上是⼀样的,尾数位最⼤是 52 位,因此 JS 中能精准表⽰的最⼤整数是 Math.pow(2, 53),⼗进制即9007199254740992。
⼤于 9007199254740992 的可能会丢失精度
js arguments19007199254740992 >> 000 // 共计 53 个 0
9007199254740992 + 1 >> 001 // 中间 52 个 0
2
3
9007199254740992 + 2 >> 010 // 中间 51 个 0实际上
1 2 3 49007199254740992 + 1 // 丢失9007199254740992 + 2 // 未丢失9007199254740992 + 3 // 丢失9007199254740992 + 4 // 未丢失
结果如图
以上,可以知道看似有穷的数字, 在计算机的⼆进制表⽰⾥却是⽆穷的,由于存储位数限制因此存在“舍去”,精度丢失就发⽣了。
想了解更深⼊的分析可以看这篇论⽂(⼜长⼜臭):
三、解决⽅案
对于整数,前端出现问题的⼏率可能⽐较低,毕竟很少有业务需要需要⽤到超⼤整数,只要运算结果不超过 Math.pow(2, 53) 就不会丢失精度。
对于⼩数,前端出现问题的⼏率还是很多的,尤其在⼀些电商⽹站涉及到⾦额等数据。解决⽅式:把⼩数放到位整数(乘倍数),再缩⼩回原来倍数(除倍数)
1 2// 0.1 + 0.2
(0.1*10 + 0.2*10) / 10 == 0.3 // true
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论