所以我有一个作业分配,我们需要在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。)“
我希望有人能解释一下我说的是什么,我并不是真正在寻找代码示例,只是为了理解问题。
答案 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
的概率是多少?数字1
至99
具有相同的概率,即1/101
。但是0
的概率为2/101
,因为当rand()
返回0
且rand()
返回100
时,表达式rand() % 100
将为等于0
。因此0
的出现频率可能会高于其他任何数字,实际上是其他数字的两倍。因此,我们使用rand() % 100
分配2位数字是不统一的。
现在,本文提出了解决该问题的方法。提议的解决方案是将0
到RAND_MAX
区域分成100个偶数部分,以便每个部分中的数字具有相同的概率。然后滚动rand()
,查看数字在哪个区域结束。如果RAND_MAX
是2147483647
,例如我们得到一个数字279172968
,我们可以看到它以第13个区域结尾-在RAND_MAX / 100 * 13 = 279172868
和RAND_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;
}
答案 2 :(得分:1)
您可以找到有关SO的相关代码。例如,下面的rand_int()
代码基于整数代码,用于回答
Is this C implementation of the Fisher-Yates shuffle correct?(尤其是answer的Roland 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中的一些外部引用也很有用。