我应该使用std::seed_seq来种子std::mt19937吗
Should I use std::seed_seq to seed std::mt19937?
random_device生成的624个整数直接用于种子mt19937可以吗?我应该使用seed_seq吗?
class RDSeq {
public:
template <typename It>
void generate (It first, It last) const {
std::random_device rd {};
std::generate(first, last, std::ref(rd));
}
};
std::mt19937 random {};
RDSeq seq {};
random.seed(seq);
简单的答案是,不需要,所有Mersenne Twister构造函数都会在任何状态下调用seed_seq
,而不管它的大小。
这是我为填充Mersenne Twister的初始状态而编写的代码。
template <typename T = std::uint32_t, typename Enable = void>
class Mersenne;
template <typename T>
using AllowForUnsigned = std::enable_if_t<std::is_unsigned_v<T>>;
template <typename T>
class Mersenne<T, AllowForUnsigned<T>>
{
public:
Mersenne();
T operator()();
using result_type = T;
static constexpr result_type min();
static constexpr result_type max();
private:
using Twister = std::conditional_t<sizeof(T) <= 4, std::mt19937, std::mt19937_64>;
Twister engine_;
};
// Mersenne class implementation
template <typename T>
Mersenne<T, AllowForUnsigned<T>>::Mersenne()
{
// Proper seeding of mt19937 taken from:
// https://kristerw.blogspot.com/2017/05/seeding-stdmt19937-random-number-engine.html
// Body walkthrough at end of file
std::random_device rd;
std::array<T, Twister::state_size> seed_data;
std::generate_n(std::begin(seed_data), seed_data.size(), std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
engine_ = Twister(seq);
}
这是一个可点击的链接,我把它改编成了一个播种Mersenne Twister的课程。该类的核心在我上面包含的默认构造函数中。这个想法就像你说的,用种子数据填充整个19937位状态。
全面实施就在这里。其他大部分内容都是为了提供与<random>
中的发行版的兼容性。有很多针对课堂环境的评论。值得一提的是,除非random_device
能够访问真熵,否则它将使用创建种子值的确定性方法。seed_seq
也是确定性的,但如果random_device
至少有熵源,它可以在一定程度上得到缓解注意:seed_seq
也在Mersenne Twister构造函数上调用,因此即使您只提供32位状态,也会生成完整的状态,但这并不理想:link
简而言之,只提供32位的初始状态将导致PRNG永远不会生成某些值。人们可能会争辩说,这对于游乐场来说已经足够了,或者如果你总是通过分发来过滤它,那就不那么重要了,我认为这是一个公平的观点。但与此同时,永远不会选择某些值的PRNG和rand()
一样糟糕。
其他人也会说,一旦你开始关心这个问题,C++标准库(如果你说STL,这里的人会发疯,虽然他们在技术上是正确的,但我从未进行过真诚的技术讨论(<random>
对你来说可能根本不够好。它们不是加密安全的PRNG,并且很容易被错误使用,比如被允许对具有19937位状态大小的PRNG使用32位。
编辑:我的构造函数构建了一个seed_seq
;我只是试图保证调用一个特定的构造函数。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 使用一个考虑到std::map中键值的滚动或换行的键
- 我应该使用std::seed_seq来种子std::mt19937吗
- 我应该使用从std::random_device种子的随机引擎,还是每次都使用std::random_device
- 如何更改 std::hash<> 中的默认种子?
- ' std::shuffle '是否保证在不同向量上具有相同种子的相同顺序?