C中产生随机数的rand%100的问题

时间:2019-04-08 22:21:14

标签: c

所以我有一个作业分配,我们需要在C中生成1到100之间的随机数。我有一个工作示例,其中int i = rand()%100; 但是根据技术上不正确的作业,我实际上并没有得到。作业说明如下

“ 1.1我们使用随机数生成器来模拟公交车的到达时间。===> rand()函数。rand()函数将伪随机数0返回给RAND_MAX(在Linux中为2 ^ 31-1)。要生成一个随机数rn,介于0.0和1.0之间; rn = rand()/ RAND_MAX。(顺便说一下,很多人在下面创建例如2位数的随机数。r_num = rand()%100;因为%100是0到99,但这是错误的。生成2位数随机数的正确方法是:将0-RAND_MAX分成10个间隔,看看随机数落在哪里,间隔时间为= RAND_MAX / 100然后,通过以下方式将其映射到0-99之一:0 1 2 3 ......... 99 0 it 2 * it 3 * it 99 * it到RAND_MAX如果rand()返回数字在(12 * it)和(13 * it)之间,两位数的随机数是12。)“

我希望有人能解释一下我说的是什么,我并不是真正在寻找代码示例,只是为了理解问题。

3 个答案:

答案 0 :(得分:6)

那里有两个问题,都与模运算符的工作方式有关。当您将a除以b时,a % b有效地为您提供了余数。因此,让我们假设我们正在以4为模计算数字。我们还假设RAND_MAX = 6,因为我真的不希望表中有32768+行。

  a | a % 4
------------
  0 | 0
  1 | 1
  2 | 2
  3 | 3
  4 | 0
  5 | 1
  6 | 2

因此,如果您使用方法来生成1到4之间的随机数,则会遇到两个问题。首先,一个简单的数字:生成的数字介于0和3之间,而不是1和4之间。取模运算符的结果将始终在0和模之间。

另一个问题更加微妙。如果RAND_MAX不均匀地除以模数,则每个数字的机率将不同。在我们的示例中,有两种方法可以使0到2,但是只有一种方法可以使3变为3。因此3的发生率约为14.3%,其他数字的发生率约为28.6%。为了获得均匀的分布,您需要找到一种方法来处理RAND_MAX分配不均的情况。

答案 1 :(得分:1)

RAND_MAX通常为2^31 - 1,因此等于2147483647

但是为简单起见,我们假设我们有一个非常奇怪的系统,RAND_MAX = 100(因此rand()可以将0返回到100,即101个数字)。并假设rand()函数具有理想的uniform distribution

现在,rand() % 100的概率是多少?数字199具有相同的概率,即1/101。但是0的概率为2/101,因为当rand()返回0rand()返回100时,表达式rand() % 100将为等于0。因此0的出现频率可能会高于其他任何数字,实际上是其他数字的两倍。因此,我们使用rand() % 100分配2位数字是不统一的。

现在,本文提出了解决该问题的方法。提议的解决方案是将0RAND_MAX区域分成100个偶数部分,以便每个部分中的数字具有相同的概率。然后滚动rand(),查看数字在哪个区域结束。如果RAND_MAX2147483647,例如我们得到一个数字279172968,我们可以看到它以第13个区域结尾-在RAND_MAX / 100 * 13 = 279172868RAND_MAX / 100 * 14 = 300647704之间。

我们看到,该解决方案也存在缺陷,当0不等于RAND_MAX时,不可能将RAND_MAX % 1000分成100个偶数部分

我认为唯一可行的解​​决方案是丢弃所有大于RAND_MAX / 100 * 100的数字(使用C整数算法)。其余的数字将具有均匀的分布,最大值可以被100整除,因此使用其余的数字,我们可以rand() % 100。像这样:

int get_2_digit_number() {
      int r = 0;
      while (1) {
          r = rand();
          if (r > (RAND_MAX / 100 * 100)) { 
              continue;
          }
          break;
      }
      return r % 100;
}

答案 2 :(得分:1)

您可以找到有关SO的相关代码。例如,下面的rand_int()代码基于整数代码,用于回答 Is this C implementation of the Fisher-Yates shuffle correct?(尤其是answerRoland Illig):

static size_t rand_int(size_t n)
{
    size_t limit = RAND_MAX - RAND_MAX % n;
    size_t rnd;

    while ((rnd = rand()) >= limit)
        ;
    return rnd % n;
}

想法是您计算并忽略rand()返回的大值,这会导致结果有偏差。当返回一个较大的值时,可以忽略它并尝试下一个值。很少需要对rand()进行两次以上的调用。

您可能会发现Shuffle array in C中的一些外部引用也很有用。