繁体   English   中英

不止一次播种伪随机数发生器的问题?

[英]Issues with seeding a pseudo-random number generator more than once?

我已经看到了很多关于每次执行不多次伪随机数生成器的建议,但从未附带过彻底的解释。 当然,很容易理解为什么以下(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 :s构造函数快速连续多次调用,每次调用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 这根本不是随机的。

如果你的种子是可预测的,它就在这里,因为你只是递增它,rand()的输出也是可预测的。

这实际上取决于你为什么要生成随机数,以及“随机”对你来说是一个可接受的随机数。 在您的示例中,它可以快速连续地避免重复,这对您来说可能已经足够了。 毕竟,重要的是它运行。

几乎在每个平台上都有比rand()生成随机数的更好方法。

嗯,这是额外的处理,不需要做。

在那种情况下,我只是在循环开始之前使用基于时间的种子调用构造函数一次。 这将保证随机结果,而无需为每次迭代更改种子的额外开销。

我不认为你的方法比那随机。

您可以将随机数生成(这不再是严格意义上的实现方式,而是作为说明)作为值表。 如果你记得在统计数据中做任何这样的东西做简单的随机样本,种子基本上会告诉你在随机数的大表中开始的行和列。 由于我们已经可以假设数字已经正常分布,因此一次又一次地重新播种是不必要的。

不止一次播种没有额外的好处,因为这应该足够好(取决于应用)。 如果确实需要“更多”随机数,则有许多随机数生成方法。 我能想到的一个案例是以线程安全的方式生成随机数。

虽然您的解决方案是可以接受的,但您的数字不会比在全球范围内播种一次更随机。 srand一般不应该属于构造函数。 如果您想支持随机数,请在程序启动时播种一次,然后忘记它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM