我观察到rand()库函数在循环中只被调用一次时,它几乎总是产生正数。
for (i = 0; i < 100; i++) {
printf("%d\n", rand());
}
但是当我添加两次rand()调用时,生成的数字现在有更多的负数。
for (i = 0; i < 100; i++) {
printf("%d = %d\n", rand(), (rand() + rand()));
}
有人能解释一下为什么我在第二种情况下看到负数吗?
PS:我在循环之前将种子初始化为srand(time(NULL))。
这是对对这个回答的评论中提出的问题的澄清的回答,
我添加的原因是为了避免在我的代码中使用“0”作为随机数。Rand ()+ Rand()是我脑海中迅速出现的肮脏解决方案。
问题是避免0。提议的解决方案(至少)存在两个问题。一个是,正如其他答案所指出的,rand()+rand()可以调用未定义的行为。最好的建议是永远不要调用未定义的行为。另一个问题是,不能保证rand()不会连续两次产生0。
下面的语句拒绝0,避免未定义的行为,并且在绝大多数情况下将比两次调用rand()更快:
int rnum;
for (rnum = rand(); rnum == 0; rnum = rand()) {}
// or do rnum = rand(); while (rnum == 0);
问题是加法。rand()返回int值0…RAND_MAX。所以,如果你把其中的两个加起来,你会得到RAND_MAX * 2。如果它超过了INT_MAX,则加法的结果超出了int可以容纳的有效范围。带符号的值溢出是未定义的行为,可能导致你的键盘用外语与你对话。
由于在这里添加两个随机结果没有任何好处,所以简单的想法就是不要这样做。或者,如果可以保持和,可以在添加之前将每个结果强制转换为unsigned int。或者使用大一点的字体。注意long并不一定比int更宽,如果int至少是64位,这同样适用于long long !
结论:避免加法。它没有提供更多的“随机性”。如果需要更多的位,可以将sum = a + b * (RAND_MAX + 1)的值连接起来,但这也可能需要比int更大的数据类型。
As your stated reason is to avoid a zero-result: That cannot be avoided by adding the results of two rand() calls, as both can be zero. Instead, you can just increment. If RAND_MAX == INT_MAX, this cannot be done in int. However, (unsigned int)rand() + 1 will do very, very likely. Likely (not definitively), because it does require UINT_MAX > INT_MAX, which is true on all implementations I'm aware of (which covers quite some embedded architectures, DSPs and all desktop, mobile and server platforms of the past 30 years).
警告:
尽管在这里已经有一些评论,但请注意,将两个随机值相加并不能得到均匀分布,而是一个三角形分布,就像滚动两个骰子一样:要得到12(两个骰子),两个骰子都必须显示6。对于11,已经有两种可能的变体:6 + 5或5 + 6,等等。
所以,加法从这个方面来说也是不好的。
还要注意rand()生成的结果不是相互独立的,因为它们是由伪随机数生成器生成的。还要注意的是,该标准没有规定计算值的质量或均匀分布。
谢谢。我添加的原因是为了避免在我的代码中使用“0”作为随机数。Rand ()+ Rand()是我脑海中迅速出现的肮脏解决方案
对我来说,这听起来像是一个XY问题,为了从rand()中不得到0,你调用rand()两次,使程序变慢,有一个新的挫折,得到0的可能性仍然存在。
另一个解决方案是使用uniform_int_distribution,它在定义的间隔内创建一个随机且均匀分布的数字:
https://wandbox.org/permlink/QKIHG4ghwJf1b7ZN
#include <random>
#include <array>
#include <iostream>
int main()
{
const int MAX_VALUE=50;
const int MIN_VALUE=1;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distrib(MIN_VALUE, MAX_VALUE);
std::array<int,MAX_VALUE-MIN_VALUE> weight={0};
for(int i=0; i<50000; i++) {
weight[distrib(gen)-MIN_VALUE]++;
}
for(int i=0;i<(int)weight.size();i++) {
std::cout << "value: " << MIN_VALUE+i << " times: " << weight[i] << std::endl;
}
}
基本上rand()生成0和RAND_MAX之间的数字,在您的情况下生成2 RAND_MAX > INT_MAX。
可以对数据类型的最大值进行模数处理,以防止溢出。这当然会破坏随机数的分布,但rand只是一种快速获得随机数的方法。
#include <stdio.h>
#include <limits.h>
int main(void)
{
int i=0;
for (i=0; i<100; i++)
printf(" %d : %d \n", rand(), ((rand() % (INT_MAX/2))+(rand() % (INT_MAX/2))));
for (i=0; i<100; i++)
printf(" %d : %ld \n", rand(), ((rand() % (LONG_MAX/2))+(rand() % (LONG_MAX/2))));
return 0;
}