2010-02-03 46 views
3

的相同顺序我有以下代码:使用boost ::随机并获得数

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毫秒播种。我肯定错过了什么。

+0

如果你有充分的理由使用mt19937而不是简单地使用rand(),那么也可能有一个很好的理由来获得体面的种子。有Web服务提供真正随机的数据,以及可以购买的硬件。您可以将它们用作种子(定期),并使用PRNG在重新种子之间节省时间/延迟。 http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator – 2010-02-03 08:05:36

+0

我一定会缺少一些东西 - 编辑问题来给出更大的图片。 – Seth 2010-02-04 00:08:15

回答

6

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

创建生成器和种子它一次,那么就继续使用它。

这是假设你多次调用同一个运行中的代码。如果你做多的运行(但是仍然在您可以使用另一个不同的属性,例如进程ID来更改种子。

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

的Windows:

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

cool - 使用GetSystemTime()。是的,我正在做多次运行,我不想使用全局变量。 – Seth 2010-02-03 06:56:28

+0

由于某些原因,这仍然不适用于我 - 即使是毫秒 – Seth 2010-02-03 23:45:28

4

只有建立一个单一的随机数生成器,所以它只能播种一次:

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

我明白原则。但是,当我在课堂上使其变为静态时。我认为它应该只初始化一次。就我而言,我正在实例化运行相同随机数源代码的多个对象。当我将其设为静态时,它仍然会为每个对象生成相同的数字序列。 – Seth 2010-02-04 00:07:05

1

的第一个想法

在unix系统中,你可以尝试从/ dev /随机或/ dev/urandom的读一些字节的种子。您也可以尝试使用时间(0)+ pid +静态计数器(或伪随机序列)的组合。

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

另一种思考:

你可以宣布你的mt19937 PRNG为静态或全局,所以你永远不会失去它的状态。

第三思想:

要“快速连续产生多个图形执行上述代码多次”传中的曲线图的索引。 (例如genGraph(int graphIndex)并将其与时间(0)的输出相结合。boost::mt19937 randgen(static_cast<unsigned int>(std::time(0) + graphIndex));

0

如果你不希望只使用一台发电机,你可以创建一个种子一个发电机(时间(0)),然后使用该发生器作为种子进入其他发电机。

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

5

使用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,但我没有亲自尝试过。

+0

哇,我不知道你能做到这一点。真棒。 – GManNickG 2010-02-04 00:21:53

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原则。