对于一门课程,我试图实现并行蒙特卡罗模拟。该项目的要求之一是确切的结果应该是可重复的。在我目前的设计中,我有一份工作排队'由std::default_random_engine
实例和一组工作人员实施。一个工人从事一项工作。并将其用作自己的rng(也是std::default_random_engine
的实例)的种子,并使用该实例运行模拟。
虽然结果确实可以重复,但确实给我留下了一些问题:
- 编辑 - 在进一步研究之后,我注意到以下内容:std::default_random_engine
使用简单的线性同余生成器。它的状态只是它以前的价值。这意味着我的rng池的结果完全相同,但是换了一个。 mersenne twister(具有较大的内部状态)不会表现出这种行为:
#include <iostream>
#include <random>
int main(int argc, char** argv)
{
std::default_random_engine e1(1);
std::default_random_engine e2(e1());
std::cout << e1() << ",\n" << e2() << '\n';
std::mt19937_64 e3(1);
std::mt19937_64 e4(e1());
std::cout << e3() << ",\n" << e4() << '\n';
}
输出:
282475249,
282475249
2469588189546311528,
5601807455758261240
答案 0 :(得分:2)
这取决于。 PRNG实际上生成了很长的序列 确定性(非随机)值,基于其内部状态。 如果用于播种的PRNG与PRNG有关 播种,取决于种子如何初始化内部状态, 每个种子生成器都可以轻松生成, 最后一个值的第一个值是第二个值 在最后一个旁边,依此类推。
在实践中,你可能只需要增加 每个发电机的种子,而不是使用PRNG来获得 下一粒种子。除非您正在使用PRNG,否则这应该有效 也是增量(这将是一个非常差的PRNG)。
正如PJS在评论中指出的那样,如果你这样做,就扔掉生成的第一个随机数。一些生成器将使用非常确定的公式将种子转换为内部状态,并在生成随机数时基于旧状态返回值。
答案 1 :(得分:1)
使用rng播种rng池会产生某种偏见吗?如果它取决于使用哪个rng(可能确实如此),我应该使用哪一个?
具有良好的质量rng(任何新引入的C ++ 11,但不是旧的rand()
),基本思想的声音,但你不想使用相同的RNG来生成其他RNG的种子。原因如下:说你的“主”RNG生成序列ABCD,你用AB和CD播种其他RNG:第一个将继续到BC D ...,第二个到CD等:基本上每个正在生成相同的序列,从而进一步开始。如果您为主设备使用不同的RNG,则只有当您的某些ABC值在另一个RNG序列中巧合地靠近在一起时才会发生这种情况,这样一个RNG最终会重复开始重复另一个RNG序列。一些C ++ 11 RNG的时期非常庞大,但除了最苛刻的模拟之外,它们几乎不会发生冲突,而且这种重复不一定非常糟糕 - 取决于模拟。
此外,您可能希望确保相同的种子值不会被使用两次。 (当然,您重复的任何给定序列可能不具有统计学上的典型性,或者 - 可能同样存在问题 - 可能无法捕获非典型的极端情况,但如果您想要重复性,这是不可避免的。)
这个设计是否正确......
听起来很好,就像你描述的那样。
答案 2 :(得分:0)
只需使用内部状态向量的PRNG,以便击中重叠序列的风险接近于零。 MT,内部状态为2496字节,当然有资格。每个种子都有一个完整的2496字节种子,取自一个好的硬件源,如/ dev / urandom或random.org,并且出于实际目的,相关的几率为零。我不知道你的图书馆是否允许你使用一个全尺寸的种子,所以如果没有,找一个种子。
答案 3 :(得分:0)
众所周知的蒙特卡罗代码MCNP5 +使用此方案,在多核和MPI上运行。要实现它,您需要具有快速跳过(a.k.a.piapfrog或discard)功能的RNG。其中有不少。它们基于快速指数计算,F.Brown撰写的论文,&#34;随机数生成与任意步幅&#34;,Trans。上午。核酸研究SOC。 (1994年11月)。基本上,跳过是使用Brown方法的log(N)。
与MCNP5大致相同的最简单版本https://github.com/Iwan-Zotow/LCG-PLE63
更复杂(更慢,但质量更高)RNG在这里http://www.pcg-random.org/