我已经实施了一个C ++解决方案,用于测试各种策略以响应一系列随机事件。我汇总了在几台计算机上运行的多线程模拟的结果。
单个模拟产生一个整数结果,通常需要生成大约100个均匀随机整数,并且在保存一组聚合数据(平均值,标准差,最小值,最大值)之前重复1,000,000次。虽然这些块的结果在给定体系结构上最多可达6位有效数字,但运行完全相同程序的两台计算机之间的差异却要大几个数量级。
到目前为止,我在两台配备Intel处理器和一台AWS c3.8xlarge Windows Server实例的个人Windows笔记本上运行程序(相同的可执行文件)。在每台计算机上,正在进行的模拟快速接近不同的值。平均值之间的相对差异大约为10 ^ -3。在一台计算机上,100万块之间平均值的相对差异很少超过10 ^ -6。
该程序使用mt19937
中的<random>
随机数生成器。我使用time(NULL)
播种。
我无法想出这种不一致的原因。 Mersenne Twister被认为是蒙特卡罗模拟的声音发生器,我多次使用它,通常能够分析验证结果。我可以理解由于发电机缺陷和基础架构导致的均匀性的微小差异和转移,但是如此规模,很难理解。
答案 0 :(得分:1)
重构程序并消除不必要的操作后,结果在不同主机之间变得一致。看起来好像四舍五入的错误在各种看似相似的64位架构之间存在显着差异,并且由于某些设计缺陷,它们的积累导致了我的仿真结果的严重分歧。我要感谢@DanielKO,@ TonyD,@ amdn和@Yakk提出的宝贵建议。
一个有趣的说明:从一开始,c3.8xlarge AWS实例始终提供相同(正确)的结果。相反,Core 2遭受了最严重的打击。
答案 1 :(得分:1)
您似乎已经能够解决问题了。但是,让我向您指出代码中的一两个(可能的)问题。如果没有真正看到任何变态,那么很难为你做更多的事情。
time(NULL)
作为种子。这是一个非常低的熵源 - 这是相当糟糕的。首先,在不同机器上运行的程序的两个实例可能很好地选择相同的种子,其次,两个连续运行将仅具有略微不同的种子,这可能导致相似或至少相关的随机数。如果你为每个线程创建一个prng,那么第二点尤其糟糕(因为这样做是可行的!)因为那时所有线程可能只是创建相同的数字。至少使用seed_seq
,但更好,甚至是真正的随机来源(random_device
)。mt19937
将在其32位变体和(显着)更快的64变体以及不同的硬件和软件版本中提供相同的结果,但发行版不给你同样的保证。如果你想重现相同的结果,你应该编写自己的发行版(这是恕我直言,这是一个非常糟糕的标准设计缺陷,因为编写一个好的发行版是非常重要的...这在你的情况下不应该是必要的,只要您只需要随机分配的数字,并且永远不需要重新创建特定的数字序列。)虽然(正如我已经说过的)分布的差异不太可能导致您的问题,但这是两个符合标准的实现之间唯一的区别。鉴于此,我建议彻底检查其余代码,因为<random>
库似乎不太可能在这里出错。