与播种伪随机数生成器一次以上问题?
题
我见过不少建议未播种的伪随机数生成超过每执行一次,但从来没有伴随着一个详尽的解释。当然,很容易看出为什么以下的(C / C ++)的例子是不是一个好主意:
int get_rand() {
srand(time(NULL));
return rand();
}
因为每秒调用get_rand
几次产生重复的结果。
但不会下面的例子中仍是可接受的解决方案?
<强> MyRand.h 强>
#ifndef MY_RAND_H
#define MY_RAND_H
class MyRand
{
public:
MyRand();
int get_rand() const;
private:
static unsigned int seed_base;
};
#endif
<强> MyRand.cpp 强>
#include <ctime>
#include <cstdlib>
#include "MyRand.h"
unsigned int MyRand::seed_base = static_cast<unsigned int>(time(NULL));
MyRand::MyRand()
{
srand(seed_base++);
}
int MyRand::get_rand() const
{
return rand();
}
<强>的main.cpp 强>
#include <iostream>
#include "MyRand.h"
int main(int argc, char *argv[])
{
for (int i = 0; i < 100; i++)
{
MyRand r;
std::cout << r.get_rand() << " ";
}
}
即。即使MyRand
:构造函数快速连续叫了好几次,每次调用srand
有不同的参数。显然,这是不是线程安全的,但再也不是rand
。
解决方案
每个调用一个伪随机数生成器函数时,发电机需要一些内部状态,并产生一个伪随机数和一个新的内部状态。仔细选择用于将内部状态的算法,以便输出随机出现。
在播种随机数发生器,你基本上设置此内部状态。如果重置内部状态的一些可预见的价值,你会失去随机性的外观。
例如,一个流行的,简单的RNG是线性同余发生器。号被这样产生的:
X[n+1] = (a X[n] + c) mod m
在这种情况下,X [N + 1]是两个结果和新的内部状态。如果你每天为你在上面建议的时间播种发生器,你会得到看起来像这样的顺序:
{(ab + c) mod m, (a(b+1) + c) mod m, (a(b+2) + c) mod m, ...}
,其中b是您的seed_base
。这并不看起来是随机的。
其他提示
如果你的种子是可以预见的,它是在这里,因为你刚刚增加了,从兰特()的输出也将是可以预见的。
这真的取决于你为什么要生成随机数,以及如何“随机”是一个可以接受随机为您服务。在您的例子,它可避免快速连续地重复,这可能是配不上你。毕竟,重要的是它的运行。
在几乎每一个平台有一个更好的方法,以产生比兰特随机数()。
那么它不需要做额外的处理。
在那种情况下我刚刚与循环开始前,基于时间的种子调用构造函数一次。这将保证随机的结果,而不改变种子每次迭代的额外开销。
我不认为你的方法是任意的更多的比随机的。
可以认为随机数生成的(这是不严格真正实现明智任何更多,但用作插图)作为值的表。如果你还记得做任何这方面的东西在统计数据做简单的随机样本,种子基本上是告诉你什么行和列在您的随机数的大表开始。再接种一遍一遍仅仅是不必要的,因为我们已经可以假设号通常是已经分配。
有根本没有额外的好处在接种一次以上,因为这应该足够好(这取决于应用)。如果你确实需要“更多的”随机数,有随机数生成的方法很多。我能想到的一种情况是,以产生在一个线程安全的方式的随机数。
虽然解决方案是可接受的,你的数字将不超过一次播种它更随机的,在全球范围。函数srand一般不应该在构造函数中的归属。如果你想支持随机数,在程序启动时播种一次,忘掉它。