【问题标题】:Using boost::random and getting same sequence of numbers使用 boost::random 并获得相同的数字序列
【发布时间】:2010-02-03 06:20:17
【问题描述】:

我有以下代码:

Class B {

void generator()
{
    // creating random number generator
    boost::mt19937 randgen(static_cast<unsigned int>(std::time(0)));
    boost::normal_distribution<float> noise(0,1);
    boost::variate_generator<boost::mt19937, 
        boost::normal_distribution<float> > nD(randgen, noise);


    for (int i = 0; i < 100; i++)
    {
        value = nD();
        // graph each value
    }
}
};

Class A {

void someFunction()
{
    for(int i = 1; i <=3; i++)
    {
        std::shared_ptr<B> b;
        b.reset(new B());
        b->generator();
    }
}
};

我希望快速连续多次执行上述代码以生成多个图形。我还查看了thisstackoverflow 问题,该问题类似,但需要注意的是,当使用 time(0) 并且快速连续调用成员函数时,您仍然可能会得到相同的数字序列。

我该如何克服这个问题?

编辑:我尝试在 B 类中将 randgen 设为静态,也尝试在 A 类中将其设为全局变量,但每次 3 个图表仍然相同。我也尝试过从 GetSystemTime 毫秒播种。我一定是错过了什么。

【问题讨论】:

  • 如果您有充分的理由使用 mt19937 而不是简单地使用 rand(),那么也可能有充分的理由获得一个像样的种子。有提供真正随机数据的 Web 服务以及您可以购买的硬件。您可以将它们用作种子(定期),并使用 PRNG 来节省重新种子之间的时间/延迟。 en.wikipedia.org/wiki/…
  • 我一定遗漏了一些东西 - 编辑问题以提供更大的图景。

标签: c++ random


【解决方案1】:

一种方法是不要在每次执行代码时重新设置随机数生成器的种子。

创建生成器并为其播种一次,然后继续使用它。

假设您在同一次运行中多次调用该代码。如果您正在执行多次运行(但仍在同一秒内),您可以使用另一个不同的属性(例如进程 ID)来更改种子。

或者,您可以依赖于平台,使用 Windows GetSystemTime() 返回一个其元素之一为毫秒的 SYSTEMTIME 结构,或者使用 Linux getTimeOfDay 返回自纪元以来的微秒数。

窗户:

#include <windows.h>
SYSTEMTIME st;
GetSystemTime (&st);
// Use st.wSecond * 100 + st.wMillisecs to seed (0 thru 59999).

Linux:

#include <sys/time.h>
struct timeval tv;
gettimeofday (&tv, NULL);
// Use tv.tv_sec * 100 + (tv.tv_usec / 1000) to seed (0 thru 59999).

【讨论】:

  • 酷 - 使用 GetSystemTime()。是的,我正在多次运行,我不想使用全局变量。
  • 由于某种原因,这仍然对我不起作用——即使是毫秒
【解决方案2】:

使用 Boost.Random,您可以保存随机数生成器的状态——例如,您可以将其保存到文本文件中。这是通过流完成的。

例如,使用您的代码,在您播种生成器并运行一次后,您可以使用输出流保存状态,如下所示:

std::ofstream generator_state_file("rng.saved");
generator_state_file << randgen;

然后,当您创建一个新的生成器时,您可以使用相反的流从该文件中加载状态:

std::ifstream generator_state_file("rng.saved");
generator_state_file >> randgen;

然后使用状态生成更多的随机数,然后重新保存状态,以此类推。

如果您不想使用文件,也可以使用std::stringstream 将状态保存到std::string,但我没有亲自尝试过。

【讨论】:

  • 哇,我不知道你能做到这一点。太棒了。
【解决方案3】:

只创建一个随机数生成器,因此它只播种一次:

static boost::mt19937 randgen(static_cast<unsigned int>(std::time(0)));

【讨论】:

  • 原理我明白了。但是,当我在课堂上将其设为静态时。我认为它应该只初始化一次。就我而言,我正在实例化多个运行相同随机数源代码的对象。当我将其设为静态时,它仍然会为每个对象生成相同的数字序列。
【解决方案4】:

最初的想法

在 unix 上,您可以尝试从 /dev/random 或 /dev/urandom 读取一些字节作为种子。您也可以尝试使用 time(0) + pid + 静态计数器(或伪随机序列)的组合。

相信在windows上,你可以使用QueryPerformanceCounter来获取高性能定时器寄存器的值。

另一个想法:

您可以将您的 mt19937 prng 声明为静态或全局,这样您就永远不会丢失其状态。

第三个想法:

您希望“快速连续多次执行上述代码以生成多个图形”传递图形索引。 (例如 genGraph(int graphIndex) 并将其(add、xor 等)与 time(0) 的输出结合起来。boost::mt19937 randgen(static_cast&lt;unsigned int&gt;(std::time(0) + graphIndex));

【讨论】:

    【解决方案5】:

    迟来的答案:两个随机数生成器函数,用于将 boost 与标准方法进行比较。

    提升

    #include <boost/random.hpp>
    
    //the code that uses boost is massively non-intuitive, complex and obfuscated
    
    bool _boost_seeded_=false;
    
    /*--------------------*/int
    boostrand(int High, int Low)
    {
        static boost::mt19937 random;
        if (!_boost_seeded_)
        {
            random = boost::mt19937(time(0));
            _boost_seeded_=true;
        }
        boost::uniform_int<> range(Low,High);
        boost::variate_generator<boost::mt19937&, boost::uniform_int<> > 
            getrandom(random, range);
    
        return getrandom();
    }
    

    标准

    #include <cstdlib>
    #include <time.h>
    
    //standard code is straight-forward and quite understandable
    
    bool _stdrand_seeded_=false;
    
    /*--------------------*/int
    stdrand(int High, int Low)
    {
        if (!_stdrand_seeded_)
        {
            srand(time(0));
            _stdrand_seeded_=true;
        }
        return ((rand() % (High - Low + 1)) + Low);
    }
    

    这两个函数的结果具有相同的“随机性”。我会应用 KISS 原则。

    【讨论】:

      【解决方案6】:

      如果您不想只使用一个生成器,您可以使用种子(时间(0))创建一个生成器,然后将该生成器用作其他生成器的种子。

      time(0) 的分辨率为 1 秒。在短时间内将其多次用作种子将创建相同的生成器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-23
        • 1970-01-01
        • 2019-12-31
        • 1970-01-01
        • 2021-04-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多