在我当前的 C++11 项目中,我需要执行 M 模拟。对于每个模拟m = 1, ..., M
,我使用一个std::mt19937
对象随机生成一个数据集,构造如下:
std::mt19937 generator(m);
DatasetFactory dsf(generator);
根据https://stackoverflow.com/a/15509942/1849221和https://stackoverflow.com/a/14924350/1849221,Mersenne Twister PRNG 受益于热身阶段,目前我的代码中没有这个阶段。为方便起见,我报告了建议的代码片段:
#include <random>
std::mt19937 get_prng() {
std::uint_least32_t seed_data[std::mt19937::state_size];
std::random_device r;
std::generate_n(seed_data, std::mt19937::state_size, std::ref(r));
std::seed_seq q(std::begin(seed_data), std::end(seed_data));
return std::mt19937{q};
}
我的问题是我需要结果的可重复性,即在不同的执行中,对于每个模拟,数据集必须相同。这就是为什么在我当前的解决方案中我使用当前模拟来播种 Mersenne Twister PRNG 的原因。在我看来,使用std::random_device
阻止数据相同(AFAIK,这是 的确切目的std::random_device
)。
编辑:通过不同的执行,我的意思是重新启动可执行文件。
如何在我的代码中引入上述预热阶段而不影响可重复性?谢谢。
可能的解决方案#1
这是基于@SteveJessop 的第二个提案的暂定实现
#include <random>
std::mt19937 get_generator(unsigned int seed) {
std::minstd_rand0 lc_generator(seed);
std::uint_least32_t seed_data[std::mt19937::state_size];
std::generate_n(seed_data, std::mt19937::state_size, std::ref(lc_generator));
std::seed_seq q(std::begin(seed_data), std::end(seed_data));
return std::mt19937{q};
}
可能的解决方案#2
这是基于@SteveJassop 和@AndréNeve 共同贡献的暂定实现。该sha256
函数改编自https://stackoverflow.com/a/10632725/1849221
#include <openssl/sha.h>
#include <sstream>
#include <iomanip>
#include <random>
std::string sha256(const std::string str) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, str.c_str(), str.size());
SHA256_Final(hash, &sha256);
std::stringstream ss;
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
return ss.str();
}
std::mt19937 get_generator(unsigned int seed) {
std::string seed_str = sha256(std::to_string(seed));
std::seed_seq q(seed_str.begin(), seed_str.end());
return std::mt19937{q};
}
编译:-I/opt/ssl/include/ -L/opt/ssl/lib/ -lcrypto