在 Javascript 中使用 Math random 生成大数

0 javascript

我需要用 Math.random 生成 26 位数字,但是当我使用这个时: Math.floor(Math.random() * 100000000000000000000000000) + 900000000000000000000000000 我得到9.544695043285823e+26

Chr*_*ras 6

现代浏览器支持BigInt原始bigint类型,我们可以将其与随机生成的包含 8 字节的数组(sizeofbigint为 8 字节(64 位))结合起来。

1. 生成随机BigInt性能明智的

我们可以生成一个 16 个字符长度的随机十六进制字符串并将其直接应用于BigInt

const hexString = Array(16)
  .fill()
  .map(() => Math.round(Math.random() * 0xF).toString(16))
  .join('');

const randomBigInt = BigInt(`0x${hexString}`);

// randomBigInt will contain a random Bigint
Run Code Online (Sandbox Code Playgroud)

document.querySelector('#generate').addEventListener('click', () => {
  const output = [];
  let lines = 10;

  do {
    const hexString = Array(16)
      .fill()
      .map(() => Math.round(Math.random() * 0xF).toString(16))
      .join('');
    const number = BigInt(`0x${hexString}`);
 
    output.push(`${
        number.toString().padStart(24)
      } : 0x${
        hexString.padStart(16, '0')
      }`);
  } while (--lines > 0);

  document.querySelector('#numbers').textContent = output.join('\n');
});
Run Code Online (Sandbox Code Playgroud)
<button id="generate">Generate</button>
<pre id="numbers"><pre>
Run Code Online (Sandbox Code Playgroud)

BigInt2.从随机字节数组生成随机数

如果我们想要使用Uint8Array或者想要更多地控制位操作,我们可以结合Array.prototype.fillArray.prototype.map生成一个包含 8 个随机字节数值的数组(注意这比上面的方法慢大约 50%):

const randomBytes = Array(8)
  .fill()
  .map(() => Math.round(Math.random() * 0xFF));

// randomBytes will  contain something similar to this:
// [129, 59, 98, 222, 20, 7, 196, 244]
Run Code Online (Sandbox Code Playgroud)

然后我们使用Array.prototype.reduce初始化BigInt零值并将每个随机字节值左移其位置 X 8 位并将按位或reduce应用到每次迭代的当前值:

const randomBigInt = randomBytes
  .reduce((n, c, i) => n | BigInt(c) << BigInt(i) * 8n, 0n);

// randomBigInt will contain a random Bigint
Run Code Online (Sandbox Code Playgroud)

BigInt生成 10 个随机值的工作示例

document.querySelector('#generate').addEventListener('click', () => {
  const output = [];
  let lines = 10;

  do {
    const number = Array(8)
      .fill()
      .map(() => Math.round(Math.random() * 0xFF))
      .reduce((n, c, i) => n | BigInt(c) << BigInt(i) * 8n, 0n);
 
    output.push(`${
        number.toString().padStart(24)
      } : 0x${
        number.toString(16).padStart(16, '0')
      }`);
  } while (--lines > 0);

  document.querySelector('#numbers').textContent = output.join('\n');
});
Run Code Online (Sandbox Code Playgroud)
<button id="generate">Generate</button>
<pre id="numbers"><pre>
Run Code Online (Sandbox Code Playgroud)