在C中随机数生成的兰特%100的问题

问题描述 投票:1回答:3

所以我有一个家庭作业,我们需要生成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然而,这是错误的。生成2位数随机数的正确方法是:以10个间隔划分0-RAND_MAX并查看随机数落在何处。间隔时间是,它= RAND_MAX / 100.然后,通过以下方式将其映射到0 - 99之一:0 1 2 3 ......... 99 0它2 *它3 *它99 *它到RAND_MAX如果rand()返回一个数字之间( 12 * it)和(13 * it),2位数随机数为12.)“

我希望有人能够解释它在说什么,我不是在寻找代码示例只是对问题的理解。

c
3个回答
6
投票

那里有几个问题,都与模运算符的工作方式有关。当你用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将发生~14.3%的时间,而每个其他数字将出现~28.6%的时间。要获得统一分布,您需要找到一种方法来处理RAND_MAX不均匀分配的情况。


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()返回0和当rand()返回100时,表达式rand() % 100将等于0。所以0可以比任何其他数字更频繁地来,实际上是两倍。所以我们用rand() % 100分配的2位数字并不统一。

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

正如我们所看到的那样,解决方案也是有缺陷的,当0不等于RAND_MAX时,不可能将RAND_MAX % 100划分为0成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;
}

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中的一些外部引用也很有用。

© www.soinside.com 2019 - 2024. All rights reserved.