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

Javascript:使用crypto.getRandomValues生成一个范围内的随机数,javascript,random,cryptography,range,Javascript,Random,Cryptography,Range,我知道您可以使用此函数在JavaScript中生成一个范围内的随机数: function getRandomInt (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } 由IonuțG.Stan提供 我想知道的是,你是否可以用Math.random()而不是Math.random()生成一个更好的随机数。我希望能够生成一个介于0和10之间的数字,或者0-1,甚至10-5000之间的数字 您会注意

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

function getRandomInt (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
由IonuțG.Stan提供

我想知道的是,你是否可以用Math.random()而不是Math.random()生成一个更好的随机数。我希望能够生成一个介于0和10之间的数字,或者0-1,甚至10-5000之间的数字

您会注意到Math.random()生成的数字类似于:0.8565239671015732

getRandomValues API可能会返回以下内容:

  • 231
    Uint8Array(1)
  • 54328
    uint16阵列(1)
  • 35528741
    uint32阵列(1)
那么,如何将其转换回十进制数,以便我可以使用上面相同的范围算法?还是我需要一个新的算法

这是我试过的代码,但效果不太好

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;
}
在低端(范围0-1),它返回的0多于1。使用getRandomValues()的最佳方法是什么


非常感谢

最简单的方法可能是拒绝采样(请参阅)。例如,假设
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);
}

下面介绍了使用
window.crypto.getRandomValues()
[min..max]
范围内生成随机数的最简单方法

如果链接为TL,则为ECMAScript 2015语法代码;TR:

巫术
这很容易解决

考虑:

所以你需要做的就是用一个来自crypt的random替换Math.random

那么Math.random做什么呢
根据,Math.random()函数返回一个介于0到小于1之间的浮点伪随机数(包括0,但不包括1)

因此,我们需要一个加密随机数>=0,使用
crypto.getRandomValues
基本上为您实现这一点

console.log(rando(5,10))

这些答案中的许多都会产生有偏见的结果。这是一个公正的解决方案

function random(min, max) {
    const range = max - min + 1
    const bytes_needed = Math.ceil(Math.log2(range) / 8)
    const cutoff = Math.floor((256 ** bytes_needed) / range) * range
    const bytes = new Uint8Array(bytes_needed)
    let value
    do {
        crypto.getRandomValues(bytes)
        value = bytes.reduce((acc, x, n) => acc + x * 256 ** n, 0)
    } while (value >= cutoff)
    return min + value % range
}

如果您使用的是Node.js,则使用加密安全的伪随机crypto.randomInt更安全。如果你不知道自己在做什么,没有同行评议,就不要写这种敏感的方法

加密随机数([min,]max[,回调]) 新增版本:v14.10.0、v12.19.0

  • min
    随机范围的开始(包括)。默认值:0
  • max
    随机范围结束(独占)
  • 回调
    函数(err,n){}
返回一个随机整数n,使min{ 如果(错误)抛出错误; log(`从(0,1,2)中选择的随机数:${n}`); });
//同步
常数n=加密随机数(3);
log(`从(0,1,2)中选择的随机数:${n}`);
//带'min'参数
常数n=加密随机数(1,7);
log(`The dice rolled:${n}`);

在这里的讨论中,设计了一个更通用(int>256)的解决方案。我已冒昧地用建议的修订版编辑了这篇文章。:)请参见中的
Diceware.prototype.random
.0xFFFFFFFF=uint32.MaxValue(+1,因为Math.random包含0,但不包含1)
// Returns a random number between min (inclusive) and max (exclusive)
function getRandomArbitrary(min, max) {
    return Math.random() * (max - min) + min;
}

/**
 * Returns a random integer between min (inclusive) and max (inclusive).
 * The value is no lower than min (or the next integer greater than min
 * if min isn't an integer) and no greater than max (or the next integer
 * lower than max if max isn't an integer).
 * Using Math.round() will give you a non-uniform distribution!
 */
function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
var randomBuffer = new Int8Array(4); // Int8Array = byte, 1 int = 4 byte = 32 bit 
window.crypto.getRandomValues(randomBuffer);
var dataView = new DataView(array.buffer);
var uint = dataView.getUint32();
var randomBuffer = new Uint32Array(1);
(window.crypto || window.msCrypto).getRandomValues(randomBuffer);
var uint = randomBuffer[0];
function cryptoRand()
{
    var array = new Int8Array(4);
    (window.crypto || window.msCrypto).getRandomValues(array);
    var dataView = new DataView(array.buffer);

    var uint = dataView.getUint32();
    var f = uint / (0xffffffff + 1); // 0xFFFFFFFF = uint32.MaxValue (+1 because Math.random is inclusive of 0, but not 1) 

    return f;
}
function cryptoRand()
{
    const randomBuffer = new Uint32Array(1);
    (window.crypto || window.msCrypto).getRandomValues(randomBuffer);
    return ( randomBuffer[0] / (0xffffffff + 1) );
}
function random(min, max) {
    const range = max - min + 1
    const bytes_needed = Math.ceil(Math.log2(range) / 8)
    const cutoff = Math.floor((256 ** bytes_needed) / range) * range
    const bytes = new Uint8Array(bytes_needed)
    let value
    do {
        crypto.getRandomValues(bytes)
        value = bytes.reduce((acc, x, n) => acc + x * 256 ** n, 0)
    } while (value >= cutoff)
    return min + value % range
}