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

Using same random number generator across multiple functions

本文关键字:随机数生成器 函数      更新时间:2023-10-16

我相信随机数生成器(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仍然可以生成更多的随机数!

我已经尝试过制作"eng"extern,但这会使用g++产生错误:

错误:"eng"同时具有"extern"和初始值设定项extern std::mt19937eng(seq);

如何使随机数生成器"全局",以便可以多次使用它?

注意一刀切的规则。'"全球化是邪恶的"就是其中之一。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。。CCD_ 5块。或者,我建议使用平台特定的方法来获得真正的随机数。(在Windows上,使用Crypto API。在其他一切上,使用/dev/urandom/。)

希望这能有所帮助。

您不需要传递或声明任何内容,因为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);
...