初始化列表中的种子序列初始化
Seed sequence initialization in initialization list
我目前正在尝试实现一个使用接受拒绝方法的随机数生成器 (class)。因此,我需要不同的 C++11 随机数分布(在我的例子中是正态分布和均匀分布)。我想让随机数尽可能好,因此想使用以下内容来构建函数:
[...]
#include <random>
#include <vector>
[...]
std::vector<int> seeds(16);
std::mt19937 mt;
std::minstd_rand seed_rng(101); // random seed
for(size_t i=0;i<16;++i) seeds[i]=seed_rng();
std::seed_seq seq(seeds.begin(), seeds.end());
mt.seed(seq);
rng_normal = std::bind(ndist, std::ref(mt));
[...]
这非常有效。但是当我现在尝试将所有这些放在构造函数中时,我不能再使用种子序列的初始化了。我检查了 c++ 参考,但只遇到了 std::seed_seq::generate,这不是正确的解决方案。
有没有办法在填充向量后在我的初始化列表中构造 seed_seq ?
有关 seed_seq 的参考,请参阅此处:
http://en.cppreference.com/w/cpp/numeric/random/seed_seq
提前谢谢你的任何建议!
假设您对保留用于构建 mt19937
的 seed_seq
实例不感兴趣,您可以这样做:
struct foo
{
std::mt19937 mt;
std::normal_distribution<> ndist;
std::function<decltype(mt)::result_type()> rng_normal;
foo()
: mt{make_mersenne_twister()}
, rng_normal{std::bind(ndist, std::ref(mt))}
{}
static std::mt19937 make_mersenne_twister()
{
std::minstd_rand seed_rng(std::random_device{}()); // random seed
std::vector<int> seeds(16);
std::generate(seeds.begin(), seeds.end(), seed_rng);
std::seed_seq seq(seeds.begin(), seeds.end());
return std::mt19937{seq};
}
};
我用 std::random_device
替换了你的种子 (101
)。
保留 seed_seq
的问题在于它既不可复制也不可移动,因此将其构造委托给一个函数是不可能的,就像我使用 Mersenne Twister 一样。
我严重怀疑你的改进值不值。 std::mt19937 的单值(和默认)构造函数在 C++ 标准中指定。相当于
static constexpr size_t WS = 32;
static constexpr result_type IM = 1812433253;
static constexpr result_type default_seed = 5489u;
explicit mt19937(result_type value = default_seed)
{
state[0] = value;
for (int i = 1; i != state_size; ++i)
{
state[i] = i + IM * (state[i - 1] ^ (state[i - 1] >> (WS - 2)));
}
}
因此,它使用 XOR-SHIFT 随机数生成器来填充状态数组。考虑到参与提出这种播种算法的人员以及致力于将 <random>
纳入标准的人员,我认为假设他们知道 std::minstd_ran 但发现高于播种梅森龙卷风。
我目前正在尝试实现一个使用接受拒绝方法的随机数生成器 (class)。因此,我需要不同的 C++11 随机数分布(在我的例子中是正态分布和均匀分布)。我想让随机数尽可能好,因此想使用以下内容来构建函数:
[...]
#include <random>
#include <vector>
[...]
std::vector<int> seeds(16);
std::mt19937 mt;
std::minstd_rand seed_rng(101); // random seed
for(size_t i=0;i<16;++i) seeds[i]=seed_rng();
std::seed_seq seq(seeds.begin(), seeds.end());
mt.seed(seq);
rng_normal = std::bind(ndist, std::ref(mt));
[...]
这非常有效。但是当我现在尝试将所有这些放在构造函数中时,我不能再使用种子序列的初始化了。我检查了 c++ 参考,但只遇到了 std::seed_seq::generate,这不是正确的解决方案。
有没有办法在填充向量后在我的初始化列表中构造 seed_seq ?
有关 seed_seq 的参考,请参阅此处:
http://en.cppreference.com/w/cpp/numeric/random/seed_seq
提前谢谢你的任何建议!
假设您对保留用于构建 mt19937
的 seed_seq
实例不感兴趣,您可以这样做:
struct foo
{
std::mt19937 mt;
std::normal_distribution<> ndist;
std::function<decltype(mt)::result_type()> rng_normal;
foo()
: mt{make_mersenne_twister()}
, rng_normal{std::bind(ndist, std::ref(mt))}
{}
static std::mt19937 make_mersenne_twister()
{
std::minstd_rand seed_rng(std::random_device{}()); // random seed
std::vector<int> seeds(16);
std::generate(seeds.begin(), seeds.end(), seed_rng);
std::seed_seq seq(seeds.begin(), seeds.end());
return std::mt19937{seq};
}
};
我用 std::random_device
替换了你的种子 (101
)。
保留 seed_seq
的问题在于它既不可复制也不可移动,因此将其构造委托给一个函数是不可能的,就像我使用 Mersenne Twister 一样。
我严重怀疑你的改进值不值。 std::mt19937 的单值(和默认)构造函数在 C++ 标准中指定。相当于
static constexpr size_t WS = 32;
static constexpr result_type IM = 1812433253;
static constexpr result_type default_seed = 5489u;
explicit mt19937(result_type value = default_seed)
{
state[0] = value;
for (int i = 1; i != state_size; ++i)
{
state[i] = i + IM * (state[i - 1] ^ (state[i - 1] >> (WS - 2)));
}
}
因此,它使用 XOR-SHIFT 随机数生成器来填充状态数组。考虑到参与提出这种播种算法的人员以及致力于将 <random>
纳入标准的人员,我认为假设他们知道 std::minstd_ran 但发现高于播种梅森龙卷风。