Должен ли я использовать std :: seed_seq для посева std :: mt19937? - PullRequest
0 голосов
/ 01 ноября 2019

Это нормально, что 624 целых числа, сгенерированных random_device, напрямую используются для заполнения 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);

1 Ответ

0 голосов
/ 01 ноября 2019

Короткий ответ: вам не нужно, все конструкторы Mersenne Twister вызывают seed_seq в любом состоянии, которое вы ему предоставляете, независимо от его размера.


Это код, который я написал, чтобы заполнить начальное состояние твистера Мерсенна.

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);
}

Вот кликабельная ссылка к сообщению в блоге, которое я адаптировал в класс для посева Twister Mersenne. Мясо класса находится в конструкторе по умолчанию, который я включил выше. Идея в точности, как вы сказали, заполнить все 19937-битное состояние начальными данными.

Полная реализация здесь . Большая часть других материалов предназначена для обеспечения совместимости с дистрибутивами в <random>. Есть много комментариев, направленных на обстановку в классе. Стоит отметить, что если random_device не имеет доступа к истинной энтропии, он будет использовать детерминистский метод создания начальных значений. seed_seq также является детерминированным, но его можно смягчить до такой степени, если random_device хотя бы имеет энтропийный источник. NOTE : seed_seq также вызывается для конструкторов Mersenne Twister, поэтому даже если вы предоставите только 32-битное состояние, будет сгенерировано полное состояние, но оно не идеально: link

Короче говоря, предоставление только 32-битного начального состояния приведет к тому, что PRNG просто никогда не будет генерировать определенные значения. Люди могут утверждать, что этого достаточно для игровых площадок или что это имеет меньшее значение, если вы всегда фильтруете его через дистрибутив, и я думаю, что это справедливо. Но в то же время, PRNG, который никогда не выберет определенные значения, так же плох, как rand().

Другие также сделают так, что, как только вы начнете заботиться об этом, Стандартная библиотека C ++ (люди здесь сходят с ума, если вы говорите STL, и хотя они технически правильны, у меня никогда не былоВера, техническая дискуссия сходит с рельсов) <random> просто может быть недостаточно для вас в любом случае. Они не являются криптографически безопасными PRNG и просты в неправильном использовании, например, им разрешено использовать 32-разрядную версию для PRNG с размером состояния 19937-бит.

РЕДАКТИРОВАТЬ: Мой конструктор создает seed_seq;Я просто пытаюсь гарантировать, что конкретный конструктор будет вызван.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...