【问题标题】:How to generate random BigInt within a range in plain JavaScript (not Node.js)?如何在纯 JavaScript(不是 Node.js)的范围内生成随机 BigInt?
【发布时间】:2022-01-12 07:28:23
【问题描述】:

对于特定范围内 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() 返回一个非 BigInt . Math.random() 的示例返回 0.5427862726372646,即 16 位小数。但如果我有一个类似于 41223334444555556666667777777888888889999999997n 的 BigInt,那是一个 47 位数字,所以乘以 0.5427862726372646 * (10**46) 得到 5.4278627263726465e+45。将其包裹在BigInt 中,您将得到BigInt(0.5427862726372646 * (10**46)) 等于5427862726372646467145376115182187925303459840n。嗯……这就是解决办法吗?

41223334444555556666667777777888888889999999997n
5427862726372646467145376115182187925303459840n

结果如何?如果那是我刚刚偶然发现它试图问这个问题的解决方案。你能仔细检查一下这是否正确并确认,或许可以解释一个普通的 JavaScript 数字(带有e+45 表示),当传递给BigInt 构造函数时,会产生一个看似准确详细的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 random integer bigint


    【解决方案1】:

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

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

    Math.random() 只返回正数,因此符号位无关紧要。这意味着 Math.random() 不能产生比 2 ** 63 更多的不同值,实际上它小于那个值,因为 Math.random() 只返回 0 和 1 之间的值(这意味着根据实现没有或不是全部使用了 11 个指数位)。当您的范围大于该范围时,Math.random() 将无法生成该范围内的每个数字。在限制范围内,您的方法应该有效。

    【讨论】:

    • 是否可以生成大于2 ** 64 的随机 BigInt?使用任何可能的方法。
    • 您可以生成任意多个个位数的字符串并将它们连接在一起
    • 产生多个随机数并将生成的字符串表示形式连接起来,以便达到所需的大小。然后将此字符串用作 BigInt 构造函数中的参数。
    • Follow-up question 解决最后一个问题。
    • @MarioVarchmin:在 0 和 1 之间确实有超过 2**52 个双精度值,但是 Math.random() 指定返回值“在该范围内具有近似均匀的分布”,这有效地固定了指数。我检查了 V8 的实现:它随机分配 52 位,其他 12 位是固定的。
    猜你喜欢
    • 2016-02-10
    • 2010-12-24
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多