在多个函数中使用相同的随机数生成器
Using same random number generator across multiple functions
我相信随机数生成器 (RNG) 应该只播种一次以确保结果的分布符合预期。
我正在用 C++ 编写一个 Monte Carlo 模拟,其中包含一个主函数 ("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::mt19937 eng(seq);
如何制作随机数生成器"global"以便我可以多次使用它?
您不需要传递任何东西或声明任何东西,因为 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);
...
注意一刀切的规则。 'Globals are evil' 就是其中之一。 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/
。)
希望这对您有所帮助。
我相信随机数生成器 (RNG) 应该只播种一次以确保结果的分布符合预期。
我正在用 C++ 编写一个 Monte Carlo 模拟,其中包含一个主函数 ("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::mt19937 eng(seq);
如何制作随机数生成器"global"以便我可以多次使用它?
您不需要传递任何东西或声明任何东西,因为 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);
...
注意一刀切的规则。 'Globals are evil' 就是其中之一。 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/
。)
希望这对您有所帮助。