起因:今天在调用合约的时候发现使用 BIgInt 丢了精度。看了下发现是自己的姿势不对,记录一下问题。
const amountIn = '2e+24'
const contract = contract.function(BigInt(Number('2e+24'))
为什么会这么写呢, 因为我们前端库升级到了 ethersJS V6 版本,v6 里把 BigNumber 迁移到了 bigInt,所以我潜意识里将传的参数都转换成 BigInt 格式。而且潜意识里BigInt能处理任意精度。但是这一行代码里就踩了几个坑。
// IEEE 754 support 53-bits of mantissa
// 等于 JS 里 Number.MAX_SAFE_INTEGER: 9_007_199_254_740_991
const maxValue = 0x1fffffffffffff;
错误: Number(‘2e+24’);超过的 上述的安全值后,即会产生数据失真。
2. 概念混淆, BigInt确实能处理任意精度,但是 Number 的最大值是有限的, 不能拿错误的 Number 去给 BigInt 处理,这必❌
问:超过安全值再计算会发生什么? 失真。 这里贴了网上的一个栗子。
const max = Number.MAX_SAFE_INTEGER;
// → 9_007_199_254_740_991
max + 1;
// → 9_007_199_254_740_992 ✅
max + 2;
// → 9_007_199_254_740_992 ❌
参考链接:
etherJS仓库
BigInt:JavaScript 中的任意精度整数