如何使用 <random> 在多种类型的编译器和内核上生成相同的随机数序列?

How to generate the same random number sequence over multiple types of compilers and kernels with <random>?

问题

我需要在不同的机器和编译器上生成相同的(伪)随机数序列。如果我使用相同的内核,似乎在 g++ 中实现梅森扭曲器 (MT) 效果很好:无论我是在较新的机器上使用 g++ 4.9 还是 4.7 编译我的程序,我都会得到相同的随机数。但是,如果我使用旧内核或更改为 Visual Studio 的编译器,我会得到不同的结果。没关系,因为不能保证 mersenne_twister_engine::seed 在不同的编译器上将内部状态设置为相同。

我已经尝试过的

我认为在生成器上应用 operator<< 会产生一个独特的结果,可用于在具有 operator>> 的其他机器上设置生成器,但在 mt19937 的情况下,它似乎不工作。为了清楚起见,在计算机 A 上我有代码

mt19937 generator1A;
uniform_int_distribution<int> distribution(0, 1000);

cout << "Generating random numbers with seed 1000" << endl;

generator1A.seed(1000);
generator1A(); //to advance the state by one so operator>> will give a longer output; this is not necessary indeed
ofstream test("testseed1000.txt");
test << generator1A << endl;

for (int i = 0; i < 10; ++i)
    cout << distribution(generator1A) << endl;

它会生成 252、590、893、... 和一个长文件。我把文件传到另一台机器B,运行下面的代码:

mt19937 generator1B, generator2B;
uniform_int_distribution<int> distribution(0, 1000);

cout << "Generating random numbers with seed 1000, and with operator>>" << endl;
generator2B.seed(1000);
generator2B(); // to advance the state by one here as well

ifstream test("testseed1000.txt");

test >> generator1B;
cout << "************************" << endl;
cout << generator1B << endl;
cout << "************************" << endl;
cout << "With seed\twith operator>>" << endl;

for (int i = 0; i < 10; ++i)
    cout << distribution(generator2B) << "\t" << distribution(generator1B) << endl;

它产生

654     205
205     115
115     610

问题

您能否就如何在 Windows 上至少使用 VC++ 以及在 Debian 和 Ubuntu 上使用 g++ 生成相同的(伪)随机数提出建议?如果可能的话,我想使用 std,但我不想实现自己的 MT 引擎。

备注:

要从问题中删除变量,请尝试查看随机数引擎的输出,而不是将其输入分布。

我只是查看了 uniform_int_distribution 的几个文档页面,它没有给出任何关于如何使用统一随机数生成器的输出的说明。我不确定标准是怎么说的。

我预测你 从你的梅森扭曲器得到相同的输出,但是你将这些输出输入到 uniform_int_distribution.[=12 的两个不等价的实现中=]

如果这是真的,那么要获得相同的随机数序列,您将不得不使用分布函数的外部实现来确保您在所有系统上获得相同的结果。

该标准要求引擎通过指定默认构造的引擎必须在第 10000 次调用时生成的值(它还指定引擎的实际转换和生成算法)来跨实现生成可重现的数字。例如,对于 mt19937,标准指定 ([rand.predef]/p3):

typedef mersenne_twister_engine<uint_fast32_t,
       32,624,397,31,0x9908b0df,11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253>
       mt19937;

Required behavior: The 10000th consecutive invocation of a default-constructed object of type mt19937 shall produce the value 4123659995.

对于发行版,没有这样的要求;相反,标准说 ([rand.dist.general]/p3):

The algorithms for producing each of the specified distributions are implementation-defined.

换句话说,实现可能对分布使用不同的算法,但必须记录它们使用的算法。 MSVC 和 libstdc++ 大概使用不同的算法。

如果您想要完全的可移植性,您可以考虑使用外部实现,例如 Boost.Random 的发行版 类。