写过 JS 的人都踩过这个坑——BigInt 明明装得下,Math.sqrt 偏偏不认,今天 Safari 27 把这件事彻底原生化了
写过金融系统或者加密货币相关代码的人都知道,大数运算在 JavaScript 里是个高频坑——Number 类型精度上限是 2^53-1,超出这个范围就开始出现「2^53 + 1 === 2^53」的尴尬局面。所以大家早就转向了 BigInt。
但转过去之后又遇到一个新问题:Math 对象的数学函数全都不支持 BigInt。
// 你以为这能跑?
Math.sqrt(16n) // TypeError: Cannot convert BigInt to number
// 正确的写法是什么?先把 BigInt 转成 Number:
Math.sqrt(Number(16n)) // 4
// 精度直接丢失——16n 转成 Number 没问题,
// 但如果是 2n ** 60n(一个极大的数),转成 Number 直接变 Infinity
这是 Safari 27 之前每个大数开发者的日常:要么手写一个 bigint sqrt,要么先把精度送出去再算。今天 Safari 27 把这件事彻底原生化了。
Safari 27 实现了 TC39 Stage 1 的 BigInt Math 提案,给 BigInt 构造函数直接加了七个静态方法:
BigInt.abs(x)
BigInt.sign(x) // -1n / 0n / 1n
BigInt.sqrt(x) // 平方根,向零取整
BigInt.cbrt(x) // 立方根,向零取整
BigInt.pow(base, exp)
BigInt.min(...args)
BigInt.max(...args)
注意这些全是静态方法,和 BigInt.asIntN() 一个风格——因为 BigInt 是原始值,不是对象,不适合挂在 prototype 上。
// 现在直接跑
BigInt.sqrt(16n) // 4n
BigInt.sqrt(17n) // 4n(向零取整,不是四舍五入)
BigInt.cbrt(27n) // 3n
BigInt.cbrt(28n) // 3n
BigInt.pow(2n, 100n) // 1267650600228229401496703205376n
BigInt.min(3n, 1n, 4n, 1n, 5n, 9n) // 1n
BigInt.abs(-7n) // 7n
BigInt.sqrt 和 BigInt.cbrt 都是向零取整——这和 BigInt 的语义一致,因为 BigInt 只表示整数,不存在「.5」这样的中间状态。
真正重要的是精度不再丢失:
// 以前:想把 2^60 的平方根算出来
const x = 2n ** 60n
Math.sqrt(Number(x)) // 1073741824,但 Number(x) 本身已经不准了
// 现在:直接在 BigInt 域里运算
BigInt.sqrt(2n ** 60n) // 1073741824n,精确值
Safari 27 是第一个完整实现这个提案的浏览器引擎。TC39 Stage 1 意味着规范还可能变化,但 Safari 已经率先把它送进了稳定版——对这类提案来说,先行实现通常会推动规范走向成熟。
下一步:如果你的项目里有大数运算需求,现在可以试试 Safari 27 的 BigInt Math 了。需要注意的是 sqrt/cbrt 返回的是截断后的整数,不是四舍五入——这个行为和 BigInt 本身的语义一致,用之前心里要有数。
评论区
0 条评论
登录后可评论。