Кажется, у меня много ответов, в которых кто-то предлагает использовать <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
может и не может сделать.