c++ - 我应该使用 std::seed_seq 来播种 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,这里的人会发疯,虽然他们在技术上是正确的,但我从未有过真诚的技术讨论rails)<random>
对你来说可能还不够好。它们不是加密安全的 PRNG,而且很容易被误用,例如允许将 32 位用于具有 19937 位状态大小的 PRNG。
编辑:我的构造函数构建一个seed_seq
; 我只是试图保证调用特定的构造函数。
推荐阅读
- react-native - 更新 graphql 列中的 JSON 数据
- emotion - 如何合并样式标签
- javascript - 节点csv解析返回值在调用时返回为未定义
- graphql - GraphQL 格式返回对象
- swiftui - replaceOccurrences() 用于通过正则表达式将文本拆分为多行
- javascript - 为什么我的承诺链仍然同时执行?
- pine-script - 松脚本 - 有没有办法获得当天的收盘价,以将其用于过去的收盘系列计算[]?
- django - Django、Nginx、uWSGI sock - 内部服务器错误
- r - 下一行正在谈论的错误是什么?
- azure-powershell - 将 Azure 管道变量作为 Powershell 脚本参数发送