我见过不少建议未播种的伪随机数生成超过每执行一次,但从来没有伴随着一个详尽的解释。当然,很容易看出为什么以下的(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一般不应该在构造函数中的归属。如果你想支持随机数,在程序启动时播种一次,忘掉它。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top