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

Dan*_*zes 18 c++ random c++11

问题

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

我已经尝试过的

我认为应用于operator<<发生器会产生一个独特的结果,可以用来设置其他机器上的发生器operator>>,但是如果mt19937它似乎不起作用.为了说清楚,在计算机上AI有代码

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;
Run Code Online (Sandbox Code Playgroud)

它产生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;
Run Code Online (Sandbox Code Playgroud)

它产生了

654     205
205     115
115     610
Run Code Online (Sandbox Code Playgroud)

这个问题

你能给出如何在Windows上使用至少VC++和在Debian和Ubuntu上使用g ++生成相同(伪)随机数的建议吗?如果有可能我想使用std,我不想实现自己的MT引擎.

笔记:

  • 创建数百万个随机数然后读入不是解决方案
  • 我必须使用MSVS进行代码开发,使用unix服务器进行仿真
  • 除MT发动机外,我也很受欢迎,但我更喜欢MT

小智 12

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

我只是查看了一些文档页面uniform_int_distribution,并没有说明如何使用统一随机数生成器的输出.我不确定标准说的是什么.

我预测,你我从Google的梅森难题相同的输出,但你喂养这些产出为两个不等价的实现uniform_int_distribution.

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


T.C*_*.C. 8

该标准要求引擎通过指定默认构造的引擎必须在第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;
Run Code Online (Sandbox Code Playgroud)

必需行为:类型的默认构造对象的第10000 连续调用mt19937将产生值4123659995.

对于分发,没有这样的要求; 而标准则表示([rand.dist.general]/p3):

用于产生每个指定分布的算法是实现定义的.

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

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