Кажется, я вижу много ответов, в которых кто-то предлагает использовать <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. Этого недостаточно для заполнения 19937 бит состояния MT.Использование
std::mt19937 gen(rd());gen()
(заполнение 32 битами и просмотр первого вывода) не дает хорошего распределения вывода. 7 и 13 никогда не могут быть первым выходом. Два семени дают 0. Двенадцать семян дают 1226181350. ( Ссылка )std::random_device
может быть, а иногда и реализуется как простой ГПСЧ с фиксированным начальным значением. Следовательно, при каждом запуске может производиться одна и та же последовательность. ( Ссылка ) Это даже хуже чемtime(NULL)
.
Что еще хуже, очень легко скопировать и вставить приведенные выше фрагменты кода, несмотря на проблемы, которые они содержат. Некоторые решения этой проблемы требуют приобретения обширных библиотек, которые могут не подходить всем.
В свете этого, мой вопрос: как можно кратко, портативно и тщательно засеять mt19937 PRNG в C ++?
Учитывая вышеперечисленные проблемы, хороший ответ:
- Необходимо полностью засеять mt19937 / mt19937_64.
- Нельзя полагаться только на источник энтропии
std::random_device
илиtime(NULL)
как на ее источник. - Не следует полагаться на Boost или другие библиотеки.
- Должен уместиться в небольшом количестве строк, чтобы он выглядел хорошо вставленным в ответ.
мысли
Моя текущая мысль заключается в том, что выходные данные
std::random_device
можно объединить (возможно, с помощью XOR) соtime(NULL)
значениями, полученными в результате рандомизации адресного пространства , и жестко запрограммированной константой (которая может быть установлена во время распределения), чтобы получить максимальную отдачу от энтропии.std::random_device::entropy()
не дает четкого представления о том, чтоstd::random_device
может или не может сделать.
std::random_device
, time(NULL)
и адреса функций, затем выполняется XOR вместе , чтобы произвести своего рода источник энтропии максимальных усилий.
std::random_device
правильной реализации на платформах, на которых вы планируете запускать свою программу, и предоставлении вспомогательной функции, которая создает генератор с засеянными seed11::make_seeded<std::mt19937>()