如果我们在不同的机器上将c ++ 11 mt19937作为相同的种子,我们将获得相同的随机数序列

时间:2018-02-11 10:07:19

标签: c++ c++11 random

受到this和类似问题的启发,我想了解C ++ 11中的mt19937伪数生成器如何表现,当在两台独立的机器中时,它使用相同的输入进行播种。

换句话说,我们有以下代码;

std::mt19937 gen{ourSeed};
std::uniform_int_distribution<int> dest{0, 10000};
int randNumber = dist(gen);

如果我们在不同的时间在不同的机器上尝试此代码,我们每次都会获得相同的randNumber值序列或不同的序列吗?

在任何一种情况下,为什么会出现这种情况?

另一个问题:

无论种子如何,此代码是否会无限地生成随机数?我的意思是,例如,如果我们在一个运行数月但没有停止的程序中使用这个代码块,那么数字的生成或数字的一致性会有问题吗?

3 个答案:

答案 0 :(得分:8)

生成器将生成相同的值。

发行版可能不会,至少在不同的编译器或库版本中。该标准未将其行为指定为该详细程度。如果您希望编译器和库版本之间保持稳定,则必须滚动自己的发行版。

禁止库/编译器更改,它将以相同的顺序返回相同的值。但如果你关心自己编写的发行版。

...

所有PRNG都有模式和期限。 mt19937以2 ^ 19937-1的周期命名,这不太可能成为问题。但其他模式可以发展。 MT PRNG对许多统计测试都很强大,但它们不是密码学上安全的PRNG。

因此,如果您运行数月,这将成为一个问题将取决于您发现的问题的具体细节。但是,mt19937将是一个比你自己写的更好的PRNG。但假设攻击者可以根据过去的证据预测其未来的行为。

答案 1 :(得分:2)

  

无论种子如何,此代码是否会无限地生成随机数?我的意思是,例如,如果我们在一个运行数月但没有停止的程序中使用这个代码块,那么数字的生成或数字的一致性会有问题吗?

我们处理标准C ++的RNG称为伪随机RNG。根据定义,这是纯计算设备,具有多位状态(您可以将状态视为大位向量)和三个函数:

  • state seed2state(seed);
  • state next_state(state);
  • uint(32 | 64)_t state2output(state);

就是这样。显然,状态具有有限的大小,在MT19937的情况下为19937位,因此状态总数为2 19937 因此MT19937 next_state()函数是周期性的,最大周期不超过2 19937 。这个数字真的很大,而且很可能足以进行典型的模拟

但输出最大为64位,因此输出空间为2 64 。这意味着在大型运行期间,任何特定输出都会出现很多次。重要的是,当不仅会出现一些64位数字,而是之后的数字,之后以及之后 - 这就是您知道RNG期限的时间。

  

如果我们在不同的时间在不同的机器上尝试此代码,我们每次都会获得相同的randNumber值序列或不同的序列吗?

生成器的定义非常严格,您将获得相同的位流。例如,来自C ++标准(https://timsong-cpp.github.io/cppwp/rand

的MT19937
class mersenne_twister_engine {
...
static constexpr result_type default_seed = 5489u;
...

和函数seed2state描述为(https://timsong-cpp.github.io/cppwp/rand#eng.mers-6

效果:构造一个mersenne_twister_engine对象。将X -n 设置为值mod 2 w 。然后,迭代地为i = -n,...,-1,将X i 设置为...

函数next_state与第10000次调用时的测试值一起描述。标准说(https://timsong-cpp.github.io/cppwp/rand#predef-3

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


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

我使用的四大编译器(GCC,Clang,VC ++,Intel C ++)产生了相同的MT19937输出。

另一方面,发行版没有很好地指定,因此在编译器和库之间有所不同。如果您需要可移植的发行版,您可以自己动手或使用Boost或类似库中的内容

答案 2 :(得分:0)

任何带有种子的伪RNG都会在每台机器上为每次相同的种子提供相同的序列。发生这种情况,因为生成器只是一个(复杂的)数学函数,并且实际上没有任何关于它的随机性。大多数情况下,当你想要随机化时,你会从系统时钟中获取种子,这会不断变化,因此每次运行都会有所不同。 在计算机游戏中使用相同的序列是很有用的,例如当你有一个随机生成的世界并且想要生成完全相同的世界时,或者避免人们在随机机会的游戏中使用保存游戏作弊。