parseInt处理长数字字符串结果不准确的原因及替代方案咨询
问题原因
JavaScript 中的所有Number类型本质都是双精度64位浮点数,该类型能安全表示的整数范围是 -2^53 + 1 到 2^53 - 1(即 -9007199254740991 到 9007199254740991),这个范围边界也可以通过内置常量Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER直接获取。
你拼接得到的数字字符串422213681420202218对应的数值远大于2^53 - 1,已经超出了安全整数范围:
超出安全整数范围的整数无法被双精度浮点数精确表示,相邻的整数会被映射为同一个浮点数存储,因此
parseInt转换后会出现精度丢失、数值和原始字符串不匹配的问题。
可行替代方案
- 方案1:针对当前求各位和的场景,完全不需要将整串转为数值,直接遍历拼接得到的数字字符串,逐位转为数字累加即可,从根源上规避大整数精度问题,示例逻辑如下:
// 第一次求和直接遍历字符串,不需要转整数 let answer = 0; for (let c of temp) { answer += parseInt(c); } // 后续k-1次对已得到的小数值求各位和即可 for (let l = 1; l < k; l++) { answer = sumDigits(answer); }
- 方案2:如果确实需要完整保留大整数的精度,可以使用ES2020新增的
BigInt类型处理,直接将字符串传入BigInt构造函数即可,不会出现精度丢失:
let answer = BigInt(temp); // 后续对BigInt做运算时注意所有操作数都要转为BigInt类型
parseInt的使用局限梳理
- 只能安全转换范围在
Number.MIN_SAFE_INTEGER到Number.MAX_SAFE_INTEGER之间的整数字符串,超出范围的整数会丢失精度 - 如果传入的字符串开头有非数字字符,会截断到第一个合法数字位置开始转换,没有合法数字则返回
NaN - 默认会自动识别前缀为
0x/0X的字符串为十六进制,传入第二个参数指定进制可以规避该歧义
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

