0%

JavaScript大整数精度丢失问题

遇到一个case,后端通过ajax向前端返回JSON数据时,其中有一个较大的整数199941234302361658,页面却展示为199941234302361660。 研究了一下,JavaScript 只有一种数字类型:Number,Number是双精度浮点数,与许多其他编程语言不同,JavaScript 不定义不同类型的数字,比如整数、短、长、浮点等等。因此在JavaScript中,数字不分为整数类型和浮点类型,所有的数字都是浮点类型。

在表达整数时,Number能表示的整数范围是\([-2^{53}, 2^{53}]\)。因为Number有8个字节64位,其中包括1位符号位,11位指数位,52位尾数位。

可以用Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER查看最大安全整数、最小安全整数。

1
2
const max = Number.MAX_SAFE_INTEGER;
9007199254740991
注意最大安全整数是\(2^{53}-1\),所以它还能正确地加一次1:
1
2
max + 1
9007199254740992
再加一次,就出问题了:
1
2
max + 2
9007199254740992
可以发现Number.MAX_SAFE_INTEGER是一个长度为16位的整数,因此需要牢记数字长度达到16位及以上时就需要警惕了。

在这个case中,JSON反序列化时把数字转化为了Number类型,所以导致了精度溢出的问题,在返回JSON时把这个字段改为字符串型即可。