如何在纯 JavaScript(不是 Node.js)的范围内生成随机 BigInt?

How to generate random BigInt within a range in plain JavaScript (not Node.js)?

JavaScript中的基本随机数在特定范围内有这个很好的问题:

Generating random whole numbers in JavaScript in a specific range?

function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

如何在普通 JavaScript 中使用 BigInt 做同样的事情(即不使用 Node.js 或使用 crypto.randomBytes)?跨环境工作的东西(支持 BigInt)?

(大声思考...) 您不能只更改要附加 n 的公式中的数字以使它们成为 BigInt,因为 Math.random() returns 一个非 BigInt。例如Math.random()returns0.5427862726372646,即16位小数。但是如果我有一个类似于 41223334444555556666667777777888888889999999997n 的 BigInt,那是一个 47 位数字,所以乘以 0.5427862726372646 * (10**46) 得到 5.4278627263726465e+45。将其包装在 BigInt 中,您会得到 BigInt(0.5427862726372646 * (10**46)) 等于 5427862726372646467145376115182187925303459840n。嗯...这是解决方案吗?

41223334444555556666667777777888888889999999997n
5427862726372646467145376115182187925303459840n

结果如何?如果那是我刚才偶然发现的解决方案,试图问这个问题。您能否仔细检查并确认这是正确的,并解释一下当传递给 BigInt 构造函数时,常规 JavaScript 数字(具有 e+45 表示)如何产生看似准确详细的 BigInt值?那我试试看吧

BigInt(Math.random() * (10 ** 45))
// => 329069627052628509799118993772820125779492864n

嗯。没看懂,Math.random()原来只有16位?

const rand = Math.random()
// => 0.7894008119121056

BigInt(rand * (10 ** 45))
// => 789400811912105533187528403423793891092987904n

这没有意义,我本以为:

789400811912105600000000000000000000000000000

也就是说,0.7894008119121056 移动了 45 位小数。

不确定为什么会这样,是不是只在 Chrome 中?

最后一个测试:

console.log('10 ** 35 <=> 10 ** 45')
console.log(rint(10 ** 35, 10 ** 45).toString())
console.log('10 ** 35 <=> 10 ** 45')
console.log(rint(10 ** 35, 10 ** 45).toString())
console.log('10 ** 20 <=> 10 ** 40')
console.log(rint(10 ** 20, 10 ** 40).toString())
console.log('10 ** 20 <=> 10 ** 40')
console.log(rint(10 ** 20, 10 ** 40).toString())

function rint(min, max) {
  return BigInt(Math.random() * max - min + 1) + BigInt(min)
}

我得到例如:

10 ** 35 <=> 10 ** 45 485253180777775593983353876860021068179439616n
10 ** 35 <=> 10 ** 45 178233587725359997576391063983941630941986816n
10 ** 20 <=> 10 ** 40 8245114695932740733462636549119006474240n
10 ** 20 <=> 10 ** 40 7214182941774644957099293094661617352704n

那么这是一个正确的实现吗? 那么你将如何实现它以获取从 0 到任意大的 BigInt 的随机整数?

JavaScript 数字始终按照国际 IEEE 754 标准存储为双精度浮点数。

此格式以 64 位存储数字(其中数字(分数)存储在位 0 到 51 中,指数存储在位 52 到 62 中,符号存储在位 63 中)。

Math.random() returns 只有正数,因此符号位无关紧要。这意味着 Math.random() 不能产生更多 2 ** 63 不同的值,实际上它小于那个,因为 Math.random() returns 只能产生 0 到 1 之间的值(这意味着取决于实现 none 或并非所有 11 个指数位都被使用)。当您的范围大于该范围时,Math.random() 将无法生成该范围内的每个数字。在限制范围内,您的方法应该有效。