在 C++11 中保存和加载随机数生成器状态

Save and Load Random Number Generator State in C++11

这个问题之前已经被问过(Whosebug)但是(接受的)答案并不令人满意。

以下示例保存和加载状态,但取决于生成值的数量,它是否有效:

#include <fstream>
#include <iostream>
#include <random>
#include <cassert>

int main()
{
  const int preN = 4;
  const int middleN = 0;

  // initialize randGen
  std::mt19937 randGen1;
  std::normal_distribution<double> distribution1;


  // print some initial random numbers
  for (int i=0;i<preN;++i)
    std::cout << distribution1(randGen1)<<" ";

  // save state
  std::cout << std::endl << "Saving...\n";
  {
    std::ofstream fout("seed.dat");
    fout << randGen1;
  }

  // maybe advance randGen1
  for (int i=0;i<middleN;++i)
    std::cout << distribution1(randGen1)<<" ";

  // load saved state into randGen2 
  std::cout << std::endl << "Loading...\n";
  std::ifstream fin("seed.dat");
  std::mt19937 randGen2;
  fin >> randGen2;
  std::normal_distribution<double> distribution2;

  // are both randGen equal?
  assert(randGen1 == randGen2);

  // print numbers from both generators
  std::cout << "Generator1\tGenerator2\n";
  std::cout << distribution1(randGen1) << "\t"
            << distribution2(randGen2) << "\n";

  return 0;

}    

使用这些参数,它可以像预期的那样工作。但是,如果我设置 preN=3 输出如下:

0.13453 -0.146382 0.46065 
Saving...

Loading...
Generator1  Generator2
-1.87138    0.163712

为什么断言不适用?现在我设置 preN=3middleN=1 并且输出是

0.13453 -0.146382 0.46065 
Saving...
-1.87138 
Loading...
Generator1  Generator2
0.163712    0.163712

如果我将 middleN 设置为任何大于 1 的值,则断言适用。 谁能解释这是怎么回事?我做错了什么或没理解?

已在 Linux

上使用 GCC5.4.0 和 CLANG3.8.0 进行测试

问题不在于您的随机数生成器的状态。问题是您的 发行版的 状态。是的,发行版也可以有状态。

您可以通过使用 reset 重置正态分布的状态来获得相同的值。或者,您也可以 preserve and reconstitute 分布的状态,使用 <<>>.

感谢上面 Nicol Bolas 的回答,我可以在下面添加更正的代码:

#include <fstream>
#include <iostream>
#include <random>
#include <cassert>

int main()
{
  const int preN = 7;
  const int middleN = 0;

  // initialize another randGen
  std::mt19937 randGen1;
  std::normal_distribution<double> distribution1;

  // print some initial random numbers
  for (int i=0;i<preN;++i)
    std::cout << distribution1(randGen1)<<" ";

  // save state
  std::cout << std::endl << "Saving...\n";
  {
    std::ofstream fout("seed.dat");
    fout << randGen1;
    fout.close();
    std::ofstream fout2("distribution.dat");
    fout2 << distribution1;
    fout2.close();
  }

  // maybe advance randGen
  for (int i=0;i<middleN;++i)
    std::cout << distribution1(randGen1)<<" ";

  // load saved state into randGen2
  std::cout << std::endl << "Loading...\n";
  std::mt19937 randGen2;
  std::normal_distribution<double> distribution2;
  {
    std::ifstream fin("seed.dat");
    fin >> randGen2;
    fin.close();
    std::ifstream fin2("distribution.dat");
    fin2 >> distribution2;
    fin2.close();
  }

  // are both randGen equal?
  assert(randGen1 == randGen2);
  assert(distribution1 == distribution2);

  // print numbers from both generators
  std::cout << "Generator1\tGenerator2\n";
  std::cout << distribution1(randGen1) << "\t"
            << distribution2(randGen2) << "\n";

  return 0;
}    

以下是如何保存和恢复双浮点精度随机数的种子。整数应该类似 - 使用 jrand48 而不是 erand48。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{

     unsigned short savedseed[3];
     unsigned short currentseed[3];
     double x;

     /*-- initialize ramdom seed to whatever --*/
     currentseed[0]= 23;
     currentseed[1]= 45;
     currentseed[2]= 67;

     printf("\n");

     /*-- generate three random numbers  --*/
     x =  erand48(currentseed);     printf("%g\n", x);
     x =  erand48(currentseed);     printf("%g\n", x);
     x =  erand48(currentseed);     printf("%g\n", x);
     printf("\n");

     /*-- save seed  --*/
     memcpy(savedseed, currentseed, 3*sizeof(unsigned short));

     /*-- generate next three random numbers  --*/     
     x =  erand48(currentseed);     printf("%g\n", x);
     x =  erand48(currentseed);     printf("%g\n", x);
     x =  erand48(currentseed);     printf("%g\n", x);
     printf("\n", x);

     /*-- restore seed  --*/
     memcpy(currentseed, savedseed,  3*sizeof(unsigned short));

     /*-- generate the same three random numbers again --*/
     x =  erand48(currentseed);     printf("%g\n", x);
     x =  erand48(currentseed);     printf("%g\n", x);
     x =  erand48(currentseed);     printf("%g\n", x);
     printf("\n");  
}