0

I understand you can shuffle an array in JavaScript using a Fisher-Yates Shuffle. This however uses Math.random for it's random numbers. I was wondering if you could get a better shuffle using window.crypto.getRandomValues() for the random number source?

I have had a go below which works. The getRandomIntInRange() function uses rejection sampling and example specified here.

Please let me know if this is the right way to do it, or if you can think of a better way to do it. JSFiddle here.

$(document).ready(function()
{
    var dataArray = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14'];               
    var shuffledArray = shuffleArray(dataArray);                

    console.log(shuffledArray);
});         

function getRandomIntInRange(min, max) {

    var range = max - min + 1;
    var maxRange = 256;
    var byteArray = new Uint8Array(1);

    // Fill byteArray with 1 random number
    window.crypto.getRandomValues(byteArray);

    // If outside of range, get another
    if (byteArray[0] >= Math.floor(maxRange / range) * range)
    {
        return getRandomIntInRange(min, max);
    }

    return min + (byteArray[0] % range);
}

function shuffleArray(dataArray) {

    var counter = dataArray.length, temp, index;

    while (counter > 0)
    {
        index = getRandomIntInRange(0, counter - 1);
        counter--;

        temp = dataArray[counter];
        dataArray[counter] = dataArray[index];
        dataArray[index] = temp;
    }

    return dataArray;
}
4

1 回答 1

3

这段代码没有任何问题(尽管对数字 1 到 14 使用字符串似乎毫无意义地缓慢和复杂——仅数字 1 到 14 有什么问题?)。您当然可以自由使用您喜欢的任何 RNG 算法。但是不同的算法被设计为最适合不同的任务。一般来说,为模拟设计的 RNG 对于密码学来说是不安全的;加密安全的 RNG 可以用于模拟,但可能会太慢。如果你只想玩几场比赛,没问题。但是,如果您想模拟十亿手的二十一点或扑克,或者对数十亿个数据点进行蒙特卡洛集成,那么使用加密 RNG 可能会使您的代码从几分钟内运行到几周内运行而没有任何好处。

于 2013-08-20T12:49:50.427 回答