JS精度问题
console.log(0.1 + 0.2 === 0.3)
// 输出:0.30000000000000004
这个是一道经典的前端面试题。答案是false
console.log(0.1 + 0.2)
// 输出:0.3
为什么会出现这种情况?
js的底层逻辑
js只有一个数字类型,Number,它底层用的是双精度浮点数(64 bit),64位分成了:
- 1 位:符号位(正负)
- 11 位:指数位
- 52 位:尾数位(有效数字)
真正决定精度的是那 52 位尾数。52 位二进制能表达的有效十进制位数大约是 15~16 位。二进制里面,0.1和0.2都是无限循环小数。无限循环小数存不下,只能在某一位截断。
而下面能输出0.3是因为JS引擎最短往返字符串转换算法,其作用就是让数字优雅、干净地“显示”出来。需要注意,这个算法并没有改变数字在计算机内存中的存在形式。
整数也会碰到精度问题
博主只谈自己遇到过的两个场景:
雪花id
如果后端给前端传了一个19位整数的雪花id,你会发现后面几个数字变成000了,这就是精度导致的问题。所以我建议用string类去存储雪花id
前后端精度如何一致
如果说你碰到下单的这种情况,前端是肯定要用js的,如何去保证呢。前端去拿A+B计算了之后,得到Total,然后把A、B、Total都给后端,让后端再算一遍,得到Total2.只要Total=Total2,就说明算的没有问题。
解决精度方法
有好些个比如:放大再缩小,BigInt、容差比较(Number.EPSILON)
但实际用法当中还是用这种数学库比较稳妥,big.js、bignumber.js、decimal.js,用的时候最好在这个库上进行封装使用。