Javascript:使用 crypto.getRandomValues 生成一个范围内的随机数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18230217/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 11:07:56  来源:igfitidea点击:

Javascript: Generate a random number within a range using crypto.getRandomValues

javascriptrandomcryptographyrange

提问by user2503552

I understand you can generate a random number in JavaScript within a range using this function:

我知道您可以使用此函数在 JavaScript 中生成一个范围内的随机数:

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

Courtesy of Ionu? G. Stanhere.

Ionu 提供?G. 斯坦在这里

What I want to know is if you can generate a betterrandom number in a range using crypto.getRandomValues()instead of Math.random(). I would like to be able to generate a number between 0 and 10 inclusive, or 0 - 1, or even 10 - 5000 inclusive.

我想知道的是,您是否可以使用crypto.getRandomValues()而不是 Math.random()在某个范围内生成更好的随机数。我希望能够生成一个介于 0 和 10 之间的数字,或者 0 - 1,甚至 10 - 5000 包括在内。

You'll note Math.random() produces a number like: 0.8565239671015732.

您会注意到 Math.random() 产生一个数字,如:0.8565239671015732

The getRandomValues API might return something like:

getRandomValues API 可能返回如下内容:

  • 231with Uint8Array(1)
  • 54328with Uint16Array(1)
  • 355282741with Uint32Array(1).
  • 231Uint8Array(1)
  • 54328Uint16Array(1)
  • 355282741Uint32Array(1).

So how to translate that back to a decimal number so I can keep with the same range algorithm above? Or do I need a new algorithm?

那么如何将其转换回十进制数,以便我可以使用上述相同的范围算法?或者我需要一个新的算法?

Here's the code I tried but it doesn't work too well.

这是我尝试过的代码,但效果不佳。

function getRandomInt(min, max) {       
    // Create byte array and fill with 1 random number
    var byteArray = new Uint8Array(1);
    window.crypto.getRandomValues(byteArray);

    // Convert to decimal
    var randomNum = '0.' + byteArray[0].toString();

    // Get number in range
    randomNum = Math.floor(randomNum * (max - min + 1)) + min;

    return randomNum;
}

At the low end (range 0 - 1) it returns more 0's than 1's. What's the best way to do it with getRandomValues()?

在低端(范围 0 - 1),它返回的 0 多于 1。使用 getRandomValues() 做到这一点的最佳方法是什么?

Many thanks

非常感谢

回答by arghbleargh

The easiest way is probably by rejection sampling (see http://en.wikipedia.org/wiki/Rejection_sampling). For example, assuming that max - minis less than 256:

最简单的方法可能是拒绝抽样(参见http://en.wikipedia.org/wiki/Rejection_sampling)。例如,假设max - min小于 256:

function getRandomInt(min, max) {       
    // Create byte array and fill with 1 random number
    var byteArray = new Uint8Array(1);
    window.crypto.getRandomValues(byteArray);

    var range = max - min + 1;
    var max_range = 256;
    if (byteArray[0] >= Math.floor(max_range / range) * range)
        return getRandomInt(min, max);
    return min + (byteArray[0] % range);
}

回答by sindilevich

IMHO, the easiest way to generate a random number in a [min..max]range with window.crypto.getRandomValues()is described here.

恕我直言,这里描述了[min..max]范围内生成随机数的最简单方法。window.crypto.getRandomValues()

An ECMAScript 2015-syntax code, in case the link is TL;TR:

ECMAScript 2015 语法代码,以防链接为TL;TR

function getRandomIntInclusive(min, max) {
    const randomBuffer = new Uint32Array(1);

    window.crypto.getRandomValues(randomBuffer);

    let randomNumber = randomBuffer[0] / (0xffffffff + 1);

    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(randomNumber * (max - min + 1)) + min;
}