所以我有一个家庭作业,我们需要生成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.)“
我希望有人能够解释它在说什么,我不是在寻找代码示例只是对问题的理解。
那里有几个问题,都与模运算符的工作方式有关。当你用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不均匀分配的情况。
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;
}
您可以在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中的一些外部引用也很有用。