好吧,我开始失去理智。我想做的只是随机的0到410之间的数字,根据this页面,我的代码应该这样做。因为我想要一个随机数而不是伪随机数,所以我也使用srand(),例如this线程告诉我这样做。但这不起作用。我得到的只是一个数字,取决于我上次执行以来的时间。如果我尽可能快地执行它,数字通常比最后一个数字高6个数字,如果我等待更长时间,它会更高,等等。当它达到410时,它会回到0并重新开始。我错过了什么?
编辑:哦,如果我删除srand(time(NULL));
行,我每次运行程序时都得到相同的数字(41)。这甚至不是伪随机的,这只是一个静态数字。只是从the article I linked to above复制第一行代码仍然会给我41号码。我是“23号”续集中的明星,还是我错过了什么?
int main(void) {
srand(time(NULL));
int number = rand() % 410;
std::cout << number << std::endl;
system("pause");
}
答案 0 :(得分:6)
这就是使用弃用的随机数生成所得到的。
rand
产生一个固定的数字序列(这本身就很好),而且非常非常糟糕。
您可以通过rand
告诉srand
序列中的哪个位置。因为你的起点&#34; (称为种子 btw)取决于自1.1.1970 0:00:00 UTC以来的秒数,您的输出显然是时间依赖的。
执行您想要执行的操作的正确方法是使用C ++ 11 <random>
库。在您的具体示例中,这看起来有点像这样:
std::mt19937 rng (std::random_device{}());
std::uniform_int_distribution<> dist (0, 409);
auto random_number = dist(rng);
有关rand
邪恶的更多信息以及<random>
的优势,请查看this。
作为最后一句话,像我上面所做的那样播种std::mt19937
并不是最理想的,因为MT的状态空间远远大于你通过{{1}的单个调用得到的32位}。这对于玩具程序和您的标准学校作业来说不是问题,但作为参考:Here是我对MT整个州空间播种的看法,以及答案中的一些有用建议。
答案 1 :(得分:1)
来自手册:
time()返回自Epoch以来秒数的时间, 1970-01-01 00:00:00 +0000(UTC)。
这意味着如果您在同一秒内两次启动程序两次,您将使用相同的值初始化srand并获得相同的PRNG状态。
如果您通过调用srand
删除初始化,您将始终从rand
获得完全相同的数字序列。
答案 2 :(得分:0)
我担心你不能在那里得到真正的随机数字。内置函数旨在提供伪随机数。另外使用srand和rand,因为第一个使用与第二个相同的方法。如果你想煮真正的随机数,你必须找到一个正确的熵来源,例如与大气噪声一起工作,作为www.random.org的方法。
这里的问题在于随机性算法使用的种子:如果它是机器提供的数字,它就不可能是不可预测的。一个正常的解决方案是使用外部硬件。
答案 3 :(得分:0)
不幸的是,如果没有特定的硬件(通常太慢而不实用),你就无法从计算机上获得真正的随机数。
因此,您需要使用伪生成器 make 。但是你需要仔细使用它们。
函数rand
旨在以一种广义上满足均匀分布的统计特性的方式返回介于0和RAND_MAX之间的数字。最多可以预期绘制数字的平均值为0.5 * RAND_MAX
,方差为RAND_MAX * RAND_MAX / 12
。
通常rand
的实现是线性同余生成器,这基本上意味着返回的数字是前一个数字的函数。这可以给出令人惊讶的好结果,并允许您使用函数srand
种子生成
但是 重复使用srand
会破坏生成器的统计属性,这就是您发生的事情:您对srand
的使用与您的系统时钟时间相关。你正在观察的行为是完全可以预期的。
您应该只对srand
进行一次调用,然后使用rand
绘制一系列数字。你不能像你设定的那样轻松地做到这一点。但也有其他选择;你可以切换到一个随机数生成器(比如mersenne twister),它允许你绘制第(n)个术语,你可以将n的值作为命令行参数传递。
作为最后的评论,我在绘制数字时避免使用模数。如果您的模数不是RAND_MAX的倍数,这将产生统计偏差。
答案 4 :(得分:-3)
尝试通过时间(0)更改时间中的NULL(NULL)(这将为您提供当前的système时间)。如果它不起作用,你可以尝试通过执行时间(0)* 1000将时间(0)转换为ms。