在JavaScript中生成特定范围内的随机整数

2506

我该如何在 JavaScript 中生成在两个指定变量之间的随机整数,例如 x = 4y = 8 会输出 4, 5, 6, 7, 8 中的任意一个?


2
这里有一个有用的代码片段:https://gist.github.com/kerimdzhanov/7529623 - Dan K.K.
15
顺便提一下:对于那些使用npm并寻找快速、可靠和现成解决方案的人,可以使用lodash.random。它只需很小的空间(它仅会导入方法本身而非整个lodash),可轻松调用。 - Aurelio
如果需要加密安全,请使用https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues。 - happy
你能在关于数字范围的问题中更加明确吗?特别是零。负数呢?(“有些文献将自然数排除零,有时将自然数与零一起称为整数”。)(但是不要包含“编辑:”,“更新:”或类似内容——问题应该看起来像今天写的。) - Peter Mortensen
2
这里有很多答案回答了一些不同的问题(它们并不是真正的答案)。就像一些用户只阅读了“生成随机整数”,却从未看到“在特定范围内”的部分(甚至是带有[4; 8]示例的正文)。 - Peter Mortensen
Java的对应问题(包括删除的102个答案):*如何在Java中生成特定范围内的随机整数?* - Peter Mortensen
40个回答

18

这是我用来生成随机数的方法。

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

Math.random()返回一个在0(包括)和1(不包括)之间的数字。我们将此数字乘以范围(max-min),这将得到介于0(包括)和范围之间的数字。

例如,取random(2,5)。我们将随机数0≤x<1乘以范围(5-2=3),因此现在我们有一个数字x,其中0≤x<3。

为了强制该函数将最大值和最小值都作为包括在内,我们需要在范围计算中添加1:Math.random()*(max-min+1)。现在,我们将随机数乘以(5-2+1=4),得到一个数字x,使得0≤x<4。如果我们对此计算进行向下取整,我们将得到一个整数:0≤x≤3,每个结果都有相等的可能性(1/4)。

最后,我们需要将此转换为所请求值之间的整数。由于我们已经有了介于0和(max-min)之间的整数,因此我们可以通过将该值映射到正确的范围来简单地将其转换为正确的范围内的整数,即将最小值加上该整数。在我们的例子中,我们将介于0和3之间的整数加2,得到介于2和5之间的整数。


2
由于 high 只使用了一次,您可以使用 high-low+1 而不是单独的增量语句。此外,大多数用户希望首先出现 low 参数。 - Chris Walsh
random(2,5)0 似乎无效。 - Peter Mortensen
@PeterMortensen 语法错误。random(2,5) 运行正常。0 是什么意思? - Travis

18

使用此函数在给定范围内获取随机数:

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

这与之前的答案有何不同? - Peter Mortensen

13

这里是微软 .NET 实现的 JavaScript 中的 Random 类—

var Random = (function () {
    function Random(Seed) {
        if (!Seed) {
            Seed = this.milliseconds();
        }
        this.SeedArray = [];
        for (var i = 0; i < 56; i++)
            this.SeedArray.push(0);
        var num = (Seed == -2147483648) ? 2147483647 : Math.abs(Seed);
        var num2 = 161803398 - num;
        this.SeedArray[55] = num2;
        var num3 = 1;
        for (var i_1 = 1; i_1 < 55; i_1++) {
            var num4 = 21 * i_1 % 55;
            this.SeedArray[num4] = num3;
            num3 = num2 - num3;
            if (num3 < 0) {
                num3 += 2147483647;
            }
            num2 = this.SeedArray[num4];
        }
        for (var j = 1; j < 5; j++) {
            for (var k = 1; k < 56; k++) {
                this.SeedArray[k] -= this.SeedArray[1 + (k + 30) % 55];
                if (this.SeedArray[k] < 0) {
                    this.SeedArray[k] += 2147483647;
                }
            }
        }
        this.inext = 0;
        this.inextp = 21;
        Seed = 1;
    }

    Random.prototype.milliseconds = function () {
        var str = new Date().valueOf().toString();
        return parseInt(str.substr(str.length - 6));
    };

    Random.prototype.InternalSample = function () {
        var num = this.inext;
        var num2 = this.inextp;
        if (++num >= 56) {
            num = 1;
        }
        if (++num2 >= 56) {
            num2 = 1;
        }
        var num3 = this.SeedArray[num] - this.SeedArray[num2];
        if (num3 == 2147483647) {
            num3--;
        }
        if (num3 < 0) {
            num3 += 2147483647;
        }
        this.SeedArray[num] = num3;
        this.inext = num;
        this.inextp = num2;
        return num3;
    };

    Random.prototype.Sample = function () {
        return this.InternalSample() * 4.6566128752457969E-10;
    };

    Random.prototype.GetSampleForLargeRange = function () {
        var num = this.InternalSample();
        var flag = this.InternalSample() % 2 == 0;
        if (flag) {
            num = -num;
        }
        var num2 = num;
        num2 += 2147483646.0;
        return num2 / 4294967293.0;
    };

    Random.prototype.Next = function (minValue, maxValue) {
        if (!minValue && !maxValue)
            return this.InternalSample();
        var num = maxValue - minValue;
        if (num <= 2147483647) {
            return parseInt((this.Sample() * num + minValue).toFixed(0));
        }
        return this.GetSampleForLargeRange() * num + minValue;
    };

    Random.prototype.NextDouble = function () {
        return this.Sample();
    };

    Random.prototype.NextBytes = function (buffer) {
        for (var i = 0; i < buffer.length; i++) {
            buffer[i] = this.InternalSample() % 256;
        }
    };
    return Random;
}());

使用:

var r = new Random();
var nextInt = r.Next(1, 100); // Returns an integer between range
var nextDbl = r.NextDouble(); // Returns a random decimal

2
MS DotNet的Random类是受Ms-RSL许可下的,这意味着它受版权保护。因此,在使用这个衍生代码时要小心,因为它可能构成侵犯版权的案件基础。 - JohannesB

12

我想通过一个例子来解释:

JavaScript函数生成5到25范围内的随机整数

总体概述:

(i) 首先将其转换为范围-从0开始。

(ii) 然后将其转换为所需范围(这样就很容易完成了)。

所以,如果您想要生成5到25范围内的随机整数,则:

第一步:将其转换为范围-从0开始

从“较低/最小数字”中减去“最大值”和“最小值”。即

(5-5) - (25-5)

所以该范围为:

0-20 ...对吗?

第二步

现在,如果您希望范围内包括两个数字 - 即“0和20”,则方程将是:

数学方程: Math.floor((Math.random() * 21))

通用方程: Math.floor((Math.random() * (max-min +1)))

现在,如果我们将减去的/最小数字(即5)加到范围中,那么自动可以获得从0到20的范围=> 5到25

第三步

现在将您从方程中减去的差异(即5)加上“Math.floor”到整个方程中:

数学方程: Math.floor((Math.random() * 21) + 5)

通用方程: Math.floor((Math.random() * (max-min +1)) + min)

因此,最终函数将是:

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

11

使用计算机程序生成随机数后,如果选定的数字是初始数字的一部分或全部,则仍被视为随机数。但如果改变了选定数字,则数学家不会接受它作为随机数,并且他们可能称其为有偏差的数字。

但如果您正在开发一个用于简单任务的程序,则不需要考虑这种情况。但如果您正在开发一个用于生成像彩票程序或赌博游戏等有价值的随机数的程序,则如果您没有考虑上述情况,管理层将会拒绝您的程序。

因此,对于那些需要考虑随机数的人,这是我的建议:

使用Math.random()生成一个随机数(称之为n):

Now for [0,10) ==>  n*10 (i.e. one digit) and for[10,100) ==> n*100 (i.e., two digits) and so on. Here square bracket indicates that the boundary is inclusive and a round bracket indicates the boundary is exclusive.

然后移除小数点后面的所有内容 (即向下取整) - 使用 Math.floor()。这可以完成。

如果您知道如何读取随机数表以选择随机数,则您知道上述过程 (乘以1、10、100等) 不违反我在开始时提到的那个(因为它只改变小数点的位置)。

研究以下示例并根据需要进行开发。

如果您需要一个[0,9]的样本,那么n10的底数就是您的答案,如果您需要[0,99],那么n100的底数就是您的答案,依此类推。

现在让我们进入您的角色:

您要求特定范围内的数字。(在这种情况下,您对该范围有偏见。通过掷骰子从[1,6]中取一个数字,那么您对[1,6]有偏见,但只有当骰子没有偏差时,它才是随机数.)

因此,请考虑您的范围 ==> [78, 247] 范围的元素数量 = 247-78 +1 = 170; (因为两个边界都包含在内)。

/* Method 1: */
    var i = 78, j = 247, k = 170, a = [], b = [], c, d, e, f, l = 0;
    for(; i <= j; i++){ a.push(i); }
    while(l < 170){
        c = Math.random()*100; c = Math.floor(c);
        d = Math.random()*100; d = Math.floor(d);
        b.push(a[c]); e = c + d;
        if((b.length != k) && (e < k)){  b.push(a[e]); }
        l = b.length;
    }
    console.log('Method 1:');
    console.log(b);

/* Method 2: */

    var a, b, c, d = [], l = 0;
    while(l < 170){
        a = Math.random()*100; a = Math.floor(a);
        b = Math.random()*100; b = Math.floor(b);
        c = a + b;
        if(c <= 247 || c >= 78){ d.push(c); }else{ d.push(a); }
        l = d.length;
    }
    console.log('Method 2:');
    console.log(d);

注意:在第一种方法中,我先创建了一个包含你所需数字的数组,然后将它们随机放入另一个数组。

在第二种方法中,生成随机数字并检查它们是否在你需要的范围内。然后将其放入数组中。我生成了两个随机数,并使用它们的总和来最大化程序速度,从而使得获得有用数字的失败率最小化。但是,添加生成的数字也会导致一些偏差。因此,我建议使用第一种方法在特定范围内生成随机数。

在这两种方法中,你的控制台将显示结果(在Chrome中按F12打开控制台)。


3
"random"不一定意味着“均匀分布”。"biased"不意味着“非随机”。"random"的意思是从概率分布中抽取。 - syzygy
6
我几乎不能确定这个答案想要表达什么。但是,如果您需要像彩票号码和赌博之类的随机数字,首先不应该在客户端生成它们。其次,您需要一个加密安全的随机数生成器,而提供的算法不足以满足需求。反复调用“random”并不会使结果“更随机”。作者似乎关注偏差,但未提供防止偏差的良好算法。事实上,其他提供的简短答案产生无偏的随机数(假设底层的随机发生器是无偏的)。 - Jeff Walker Code Ranger
@JeffWalkerCodeRanger 我认为他的意思是,使用“正常”的算法[即Math.floor(Math.random() * (6 - 1 + 1) + 1)],数字1和6将比2、3、4和5被掷出的次数少。然而,这种差异基本上是微不足道的。 - oldboy

11

这里有一个可以在min和max之间(包括min和max)生成随机数字的函数。

const randomInt = (max, min) => Math.round(Math.random() * (max - min)) + min;

这与之前的答案有何不同?它有效吗? - Peter Mortensen
是的,使用Math.round函数,它适用于范围内的最小值和最大值都包含在内。 - epix
我犯了初学者的错误,提出了超过一个问题。实际上并没有容纳多个问题的能力。永远不要这样做。始终、始终、始终一次只提一个问题 - Peter Mortensen
我刚刚尝试了min=0,max=5,得到了一个分布为(10%,20%,20%,20%,20%,10%)。这就是当算法不支持包容范围时,试图作弊的惩罚。所以Math.round是有问题的。你最好使用Math.floor来获得一个独占范围,但是分布将是相等的(20%,20%,20%,20%,20%)。然后,如果你想要包容性,你可以把max加1,这就是应该的方法。 - Stephen Quan

10

对于一个具有范围的随机整数,请尝试:

function random(minimum, maximum) {
  var bool = true;

  while (bool) {
    var number = (Math.floor(Math.random() * maximum + 1) + minimum);
    if (number > 20) {
      bool = true;
    } else {
      bool = false;
    }
  }

  return number;
}

10
function getRandomInt(lower, upper)
{
    //to create an even sample distribution
    return Math.floor(lower + (Math.random() * (upper - lower + 1)));

    //to produce an uneven sample distribution
    //return Math.round(lower + (Math.random() * (upper - lower)));

    //to exclude the max value from the possible values
    //return Math.floor(lower + (Math.random() * (upper - lower)));
}

为了测试这个函数及其变体,请将以下HTML/JavaScript保存到文件中并在浏览器中打开。该代码将生成一个图表,显示一百万个函数调用的分布情况。代码还会记录边界情况,因此如果函数产生的值大于最大值或小于最小值,你就会知道。

<html>
    <head>
        <script type="text/javascript">
        function getRandomInt(lower, upper)
        {
            //to create an even sample distribution
            return Math.floor(lower + (Math.random() * (upper - lower + 1)));

            //to produce an uneven sample distribution
            //return Math.round(lower + (Math.random() * (upper - lower)));

            //to exclude the max value from the possible values
            //return Math.floor(lower + (Math.random() * (upper - lower)));
        }

        var min = -5;
        var max = 5;

        var array = new Array();

        for(var i = 0; i <= (max - min) + 2; i++) {
          array.push(0);
        }

        for(var i = 0; i < 1000000; i++) {
            var random = getRandomInt(min, max);
            array[random - min + 1]++;
        }

        var maxSample = 0;
        for(var i = 0; i < max - min; i++) {
            maxSample = Math.max(maxSample, array[i]);
        }

        //create a bar graph to show the sample distribution
        var maxHeight = 500;
        for(var i = 0; i <= (max - min) + 2; i++) {
            var sampleHeight = (array[i]/maxSample) * maxHeight;

            document.write('<span style="display:inline-block;color:'+(sampleHeight == 0 ? 'black' : 'white')+';background-color:black;height:'+sampleHeight+'px">&nbsp;[' + (i + min - 1) + ']:&nbsp;'+array[i]+'</span>&nbsp;&nbsp;');
        }
        document.write('<hr/>');
        </script>
    </head>
    <body>

    </body>
</html>

7
要获取一个在1到6之间的随机数,首先执行以下操作:
0.5 + (Math.random() * ((6 - 1) + 1))

这会将一个随机数乘以6,再加上0.5。然后通过以下方式将该数四舍五入为正整数:

Math.round(0.5 + (Math.random() * ((6 - 1) + 1))

这个功能会将数字四舍五入至最接近的整数。
或者,为了更容易理解,可以这样做:
var value = 0.5 + (Math.random() * ((6 - 1) + 1))
var roll = Math.round(value);
return roll;

一般来说,使用变量执行这个任务的代码如下:

var value = (Min - 0.5) + (Math.random() * ((Max - Min) + 1))
var roll = Math.round(value);
return roll;

从最小值中减去0.5的原因是仅使用最小值将允许您获得比最大值大1的整数。从最小值中减去0.5相当于防止最大值被四舍五入。

如果你排除了0,那么从0到0.5的范围就不需要“向下取整”了。 - ILMostro_7

7
使用以下代码,您可以在给定范围内生成不重复的随机数数组。
function genRandomNumber(how_many_numbers, min, max) {

    // Parameters
    //
    //   how_many_numbers: How many numbers you want to
    //                     generate. For example, it is 5.
    //
    //   min (inclusive):  Minimum/low value of a range. It
    //                     must be any positive integer, but
    //                     less than max. I.e., 4.
    //
    //   max (inclusive):  Maximum value of a range. it must
    //                     be any positive integer. I.e., 50
    //
    //   Return type: array

    var random_number = [];
    for (var i = 0; i < how_many_numbers; i++) {
        var gen_num = parseInt((Math.random() * (max-min+1)) + min);
        do {
            var is_exist = random_number.indexOf(gen_num);
            if (is_exist >= 0) {
                gen_num = parseInt((Math.random() * (max-min+1)) + min);
            }
            else {
                random_number.push(gen_num);
                is_exist = -2;
            }
        }
        while (is_exist > -1);
    }
    document.getElementById('box').innerHTML = random_number;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接