我应该使用std :: seed_seq播种std :: mt19937吗?

问题描述 投票:0回答:1

可以将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);
c++ random
1个回答
0
投票

简短的答案是您不需要,所有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);
}

这里是博客文章的clickable link,我将其改编为用于播种Mersenne Twister的类。该类的内容位于我上面包含的默认构造函数中。这个想法就像您说的那样,用种子数据填充整个19937位状态。

完整的实现是here。那里的大多数其他内容都是为了与<random>中的发行版兼容。有很多针对教室环境的评论。值得一提的是,除非random_device可以访问真实的熵,否则它将使用确定性的方法来创建种子值。 seed_seq也是确定性的,但是如果random_device至少具有熵源,则可以将其减轻到一定程度。 NOTE:Mersenne Twister构造函数上也调用了seed_seq,因此即使您仅提供32位状态,也会生成完整状态,但它并不理想:link

简短的故事是,仅提供32位初始状态将导致PRNG永远不会生成某些值。人们可能会争辩说,它足以满足游乐场的需求,或者如果您始终通过分布对它进行过滤,那么它的重要性就小了,我认为这很合理。但是同时,永远不会选择某些值的PRNG与rand()一样糟糕。

[其他人也会说,一旦您开始关心这个问题,C ++标准库(如果您说STL,这里的人就会发疯,尽管它们在技术上是正确的,但我从未进行过真诚的技术讨论。无论如何,<random>可能对您来说都不足够。它们不是加密安全的PRNG,并且易于误用,例如被允许对状态大小为19937位的PRNG使用32位。

编辑:我的构造函数建立了一个seed_seq;我只是试图保证特定的构造函数被调用。

© www.soinside.com 2019 - 2024. All rights reserved.