首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何从一个范围内生成一个随机整数

如何从一个范围内生成一个随机整数
EN

Stack Overflow用户
提问于 2010-03-25 00:55:53
回答 9查看 335.9K关注 0票数 117

这是之前发布的一个问题的后续:

How to generate a random number in C?

我希望能够在一个特定的范围内生成一个随机数,例如1到6来模拟骰子的边。

我该怎么做呢?

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2011-07-28 07:20:38

到目前为止,所有答案在数学上都是错误的。除非Nrand()返回的区间长度除以(即是2的幂),否则返回rand() % N不会一致地给出[0, N)范围内的数字。此外,人们不知道rand()的模块是否独立:它们可能是0, 1, 2, ...的,这是一致的,但不是非常随机的。唯一合理的假设是,rand()分布为泊松分布:任何两个大小相同的不重叠子区间的概率相等且相互独立。对于有限的值集,这意味着均匀分布,并确保rand()的值很好地分散。

这意味着更改rand()范围的唯一正确方法是将其分成方框;例如,如果RAND_MAX == 11和您想要一个1..6范围,则应将{0,1}指定为1,将{2,3}指定为2,依此类推。这些是不相交的、大小相等的间隔,因此是均匀且独立分布的。

使用浮点除法的建议在数学上是合理的,但原则上存在舍入问题。也许double是高精度的,足以让它工作;也许不是。我不知道,我也不想弄清楚;在任何情况下,答案都取决于系统。

正确的方法是使用整数运算。也就是说,您需要的内容如下所示:

#include <stdlib.h> // For random(), RAND_MAX

// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
  unsigned long
    // max <= RAND_MAX < ULONG_MAX, so this is okay.
    num_bins = (unsigned long) max + 1,
    num_rand = (unsigned long) RAND_MAX + 1,
    bin_size = num_rand / num_bins,
    defect   = num_rand % num_bins;

  long x;
  do {
   x = random();
  }
  // This is carefully written not to overflow
  while (num_rand - defect <= (unsigned long)x);

  // Truncated division is intentional
  return x/bin_size;
}

循环是获得完美均匀分布所必需的。例如,如果你得到了从0到2的随机数,而你只想要从0到1的随机数,你就一直拉,直到你得不到2;不难检查这是否以相等的概率给出了0或1。这种方法在nos在他们的答案中给出的链接中也有描述,尽管编码不同。我使用的是random(),而不是rand(),因为它有更好的发行版(如rand()的手册页所示)。

如果您想获得默认范围[0, RAND_MAX]之外的随机值,那么您必须做一些棘手的事情。也许最方便的方法是定义一个函数random_extended(),它拉取代码位(使用random_at_most())并在[0, 2**n)中返回,然后使用random_at_most()random_extended()代替random() (和2**n - 1代替RAND_MAX),以拉取一个小于< n >d28的随机值,假设您有一个可以容纳这样的值的数值类型。最后,当然,您可以使用min + random_at_most(max - min)获取[min, max]中的值,包括负值。

票数 177
EN

Stack Overflow用户

发布于 2013-07-10 01:27:56

根据@Ryan Reich的回答,我想我应该提供我的清理过的版本。第一个边界检查是不需要的,因为第二个边界检查,我已经使它迭代而不是递归。它返回最小、最大范围内的值,其中max >= min1+max-min < RAND_MAX

unsigned int rand_interval(unsigned int min, unsigned int max)
{
    int r;
    const unsigned int range = 1 + max - min;
    const unsigned int buckets = RAND_MAX / range;
    const unsigned int limit = buckets * range;

    /* Create equal size buckets all in a row, then fire randomly towards
     * the buckets until you land in one of them. All buckets are equally
     * likely. If you land off the end of the line of buckets, try again. */
    do
    {
        r = rand();
    } while (r >= limit);

    return min + (r / buckets);
}
票数 35
EN

Stack Overflow用户

发布于 2011-05-05 14:44:43

如果您知道某个范围的最大值和最小值,并且希望生成包含在该范围之间的数字,则可以使用以下公式:

r = (rand() % (max + 1 - min)) + min
票数 25
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2509679

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档