Кажется, у меня много ответов, в которых кто-то предлагает использовать <random> для генерации случайных чисел, как правило, вместе с таким кодом:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);
Обычно это заменяет какую-то "нечестивую мерзость", например:
srand(time(NULL));
rand()%6;
Мы можем критиковать старый способ, утверждая, что time(NULL) обеспечивает низкую энтропию, time(NULL) является предсказуемым, а конечный результат не является -равномерная.
Но все это верно по-новому: у него просто блестящий шпон.
-
rd()возвращает одинunsigned int. У этого есть как минимум 16 бит и, возможно, 32. Этого недостаточно, чтобы вынести бит MT 19937 бит. -
Использование
std::mt19937 gen(rd());gen()(посев с 32 битами и просмотр первого выхода) не дает хорошего распределения выходных данных. 7 и 13 никогда не могут быть первым выходом. Два семена производят 0. Двенадцать семян производят 1226181350. (Ссылка) -
std::random_deviceможет быть, а иногда и реализован как простой PRNG с фиксированным семенем. Таким образом, при каждом прогоне она может иметь одну и ту же последовательность. (Ссылка) Это еще хуже, чемtime(NULL).
Хуже того, очень легко скопировать и вставить вышеприведенные фрагменты кода, несмотря на проблемы, которые они содержат. Некоторые решения для этого требуют приобретения довольно больших библиотек, которые могут не быть подходящим для всех.
В свете этого мой вопрос: Как можно лаконично, переносимо и основательно семенить mt19937 PRNG на С++?
Учитывая вышеизложенные вопросы, хороший ответ:
- Должен полностью засеять mt19937/mt19937_64.
- Нельзя полагаться только на
std::random_deviceилиtime(NULL)в качестве источника энтропии. - Не следует полагаться на Boost или другие библиотеки.
- Должно вписываться в небольшое количество строк, чтобы оно выглядело красиво, скопировано в ответ.
Мысли
-
Моя текущая мысль состоит в том, что выходы из
std::random_deviceмогут быть размяты (возможно, через XOR) сtime(NULL), значениями, полученными из адресного пространства рандомизация и жестко закодированная константа (которая может быть установлена во время распространения), чтобы получить максимальную отдачу от энтропии. -
std::random_device::entropy()не дает хорошего указания на то, чтоstd::random_deviceможет и не может сделать.