在不使用iostream接口的情况下,存储C++ 11随机生成器状态的最佳方法是什么.我想像这里列出的第一个替代品那样做[1]?但是,此方法要求对象包含PRNG状态且仅包含PRNG状态.在partucular,它如果实现使用PIMPL模式失败(至少这是有可能重新加载状态,而不是用坏的数据加载它,当应用程序崩溃),或有与没有的PRNG对象相关联的多个状态变量与生成的序列有关.
对象的大小是实现定义的:
g++ (tdm64-1) 4.7.1sizeof(std::mt19937)==2504但是给了Ideone http://ideone.com/41vY5j给出2500我缺少像这样的成员函数
size_t state_size();const size_t* get_state() const;void set_state(size_t n_elems,const size_t* state_new);(1)应返回随机生成器状态数组的大小
(2)应返回指向状态数组的指针.指针由PRNG管理.
(3)应从std::min(n_elems,state_size())state_new指向的缓冲区中复制缓冲区
这种接口允许更灵活的状态操作.或者是否有任何PRNG:s的状态不能表示为无符号整数数组?
我已经为我在OP评论中提到的方法编写了一个简单的(-ish)测试。它显然没有经过实战考验,但这个想法已经得到体现——你应该能够从这里得到它。
由于读取的字节量比序列化整个引擎要少得多,因此两种方法的性能实际上可能相当。测试这个假设以及进一步的优化,留给读者作为练习。
#include <iostream>
#include <random>
#include <chrono>
#include <cstdint>
#include <fstream>
using namespace std;
struct rng_wrap
{
// it would also be advisable to somehow
// store what kind of RNG this is,
// so we don't deserialize an mt19937
// as a linear congruential or something,
// but this example only covers mt19937
uint64_t seed;
uint64_t invoke_count;
mt19937 rng;
typedef mt19937::result_type result_type;
rng_wrap(uint64_t _seed) :
seed(_seed),
invoke_count(0),
rng(_seed)
{}
rng_wrap(istream& in) {
in.read(reinterpret_cast<char*>(&seed), sizeof(seed));
in.read(reinterpret_cast<char*>(&invoke_count), sizeof(invoke_count));
rng = mt19937(seed);
rng.discard(invoke_count);
}
void discard(unsigned long long z) {
rng.discard(z);
invoke_count += z;
}
result_type operator()() {
++invoke_count;
return rng();
}
static constexpr result_type min() {
return mt19937::min();
}
static constexpr result_type max() {
return mt19937::max();
}
};
ostream& operator<<(ostream& out, rng_wrap& wrap)
{
out.write(reinterpret_cast<char*>(&(wrap.seed)), sizeof(wrap.seed));
out.write(reinterpret_cast<char*>(&(wrap.invoke_count)), sizeof(wrap.invoke_count));
return out;
}
istream& operator>>(istream& in, rng_wrap& wrap)
{
wrap = rng_wrap(in);
return in;
}
void test(rng_wrap& rngw, int count, bool quiet=false)
{
uniform_int_distribution<int> integers(0, 9);
uniform_real_distribution<double> doubles(0, 1);
normal_distribution<double> stdnorm(0, 1);
if (quiet) {
for (int i = 0; i < count; ++i)
integers(rngw);
for (int i = 0; i < count; ++i)
doubles(rngw);
for (int i = 0; i < count; ++i)
stdnorm(rngw);
} else {
cout << "Integers:\n";
for (int i = 0; i < count; ++i)
cout << integers(rngw) << " ";
cout << "\n\nDoubles:\n";
for (int i = 0; i < count; ++i)
cout << doubles(rngw) << " ";
cout << "\n\nNormal variates:\n";
for (int i = 0; i < count; ++i)
cout << stdnorm(rngw) << " ";
cout << "\n\n\n";
}
}
int main(int argc, char** argv)
{
rng_wrap rngw(123456790ull);
test(rngw, 10, true); // this is just so we don't start with a "fresh" rng
uint64_t seed1 = rngw.seed;
uint64_t invoke_count1 = rngw.invoke_count;
ofstream outfile("rng", ios::binary);
outfile << rngw;
outfile.close();
cout << "Test 1:\n";
test(rngw, 10); // test 1
ifstream infile("rng", ios::binary);
infile >> rngw;
infile.close();
cout << "Test 2:\n";
test(rngw, 10); // test 2 - should be identical to 1
return 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
410 次 |
| 最近记录: |