在 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=3
和 middleN=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");
}
这个问题之前已经被问过(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=3
和 middleN=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");
}