跨多个函数使用相同的随机数生成器

时间:2015-11-26 03:39:11

标签: c++ random global-variables global

我可以相信随机数发生器(RNG)只应播种一次,以确保结果的分布符合预期。

我正在用C ++编写一个蒙特卡罗模拟,它包含一个主函数(" A")多次调用另一个函数(" B"),其中有大量的随机函数数字在B中生成。

目前,我在B中执行以下操作:

void B(){
    std::array<int, std::mt19937::state_size> seed_data;
    std::random_device r;

    std::generate(seed_data.begin(), seed_data.end(), std::ref(r));
    std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); //perform warmup
    std::mt19937 eng(seq);

    std::uniform_real_distribution<> randU(0,1);

    double myRandNum = randU(eng);

    //do stuff with my random number
}

正如你所看到的,每次调用函数B时,我都会创建一个新的随机数生成器。据我所知,这是浪费时间--RNG仍然可以生成更多的随机数!

我已经尝试过制作&#34; eng&#34; extern但是使用g ++生成错误:

错误:'eng'同时具有'extern'和初始化程序extern std :: mt19937 eng(seq);

如何制作随机数生成器&#34; global&#34;这样我可以多次使用它?

2 个答案:

答案 0 :(得分:5)

小心一刀切的规则。 “全球是邪恶的”就是其中之一。 RNG 应该是一个全局对象。 (警告:每个线程都应该有自己的RNG!)我倾向于将我的包裹在单个地图中,但只需在main()开始时播种并加热一个就足够了:

std::mt19937 rng;

int main()
{
  // (seed global object 'rng' here)
  rng.dispose(10000); // warm it up

对于您的使用场景(每次调用生成多个RN),您应该在为每个函数调用创建本地分发时遇到任何问题。

另一件事:std::random_device不是你的朋友 - 它可以throw随时出于各种愚蠢的原因。确保将其打包在try .. catch块中。或者,我建议这样做,使用平台特定的方式获取真正的随机数。 (在Windows上,使用加密API。在其他所有内容中,使用/dev/urandom/。)

希望这有帮助。

答案 1 :(得分:1)

你不应该传递任何东西或宣布任何东西,因为mt19937和uniform_real_distribution之间的互动是通过全局变量。

std::array<int, std::mt19937::state_size> seed_data;
std::random_device r;

std::generate(seed_data.begin(), seed_data.end(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); //perform warmup
std::mt19937 eng(seq);


B()

...

void B() 
{

    std::uniform_real_distribution<> randU(0,1);
...