使用boost :: random并获得相同的数字序列

时间:2010-02-03 06:20:17

标签: c++ random

我有以下代码:

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();
    }
}
};

我希望快速连续多次执行上述代码以生成多个图形。我还回顾了this stackoverflow问题,这个问题很相似,但有一点需要注意,当使用time(0)并快速连续调用成员函数时,你仍然可能得到相同的数字序列。

我如何克服这个问题?

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

6 个答案:

答案 0 :(得分:6)

一种方法是每次执行代码时不重置随机数生成器。

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

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

或者,您可以使用Windows GetSystemTime()返回SYSTEMTIME结构,其中一个元素为毫秒,或者Linux getTimeOfDay返回自纪元以来的微秒数。< / p>

视窗:

#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).

答案 1 :(得分:6)

使用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::string将状态保存到std::stringstream,但我没有亲自尝试过。

答案 2 :(得分:4)

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

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

答案 3 :(得分:1)

第一个想法

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

我相信Windows,您可以使用QueryPerformanceCounter来获取高性能定时器寄存器的值。

另一个想法:

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

第三个想法:

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

答案 4 :(得分:1)

一个迟到的答案:两个随机数生成器函数,用于将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原则。

答案 5 :(得分:0)

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

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