【问题标题】:Save and Load Random Number Generator State in C++11在 C++11 中保存和加载随机数生成器状态
【发布时间】:2017-02-21 20:06:40
【问题描述】:

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

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

#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 测试

【问题讨论】:

    标签: c++ c++11 c++-standard-library mt19937


    【解决方案1】:

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

    您可以通过使用reset 重置正态分布的状态来获得相同的值。或者,您也可以使用&lt;&lt;&gt;&gt;preserve and reconstitute 分发的状态。

    【讨论】:

    • 也试过了(因为这种行为看起来很吸引人,而且我很长时间没有尝试 C++)并且可以肯定地说,uniform-dist 的行为不同!
    • @sascha:我不确定你的意思是它的行为不同。
    • 它可能没有重要的内部状态(比 normal-dist 简单得多),但这只是经验观察。这只是我的第一次试验。也许它也是。忽略我的评论。不错的答案!
    • @sascha:发行版是否具有影响其输出的状态取决于实现。
    • 您知道为什么会出现这种免费规范吗?我想不出任何充分的理由不假设这些是无状态的,除了缓存(构建一个随机池)。我也不认为 scipy 会那样做(乍一看甚至是 GSL)。
    【解决方案2】:

    感谢上面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;
    }    
    

    【讨论】:

      【解决方案3】:

      以下是如何保存和恢复双浮点精度的随机数的种子。整数应该类似 - 使用 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");  
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-01
        • 1970-01-01
        • 2013-10-30
        • 2011-08-25
        • 2014-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多