mt19937 c что это

Как использовать random_engine и mt19937 для циклов

Я создаю простую игру ASCII, которая должна разместить 3 змеи на экране. Я попытался использовать цикл для печати всех 3 змей:

Когда вызывается приведенный выше код, он печатает только одну змею. Я пробовал нестатический двигатель, и он все еще дает тот же результат. Это потому, что двигатель должен быть повторно посеян? Я также напечатал 2 змеи, создав 2 разных движка, но кажется, что это тратит много места, и если бы я хотел 10 змей, мне понадобилось бы 10 разных движков. Как вы получаете разные выходы от одного и того же random_engine и mt19937 при использовании цикла for?

Решение

Во-первых, вам не нужно больше одного генератора случайных чисел в этом случае (вам почти никогда не нужно). Также нет необходимости, чтобы он был статичным. В вопросе, который вы связали, он хотел, чтобы он был статичным, потому что генератор был внутри функции, которая вызывалась несколько раз. Каждый раз, когда вызывали функцию, генератор создавался с почти одинаковым начальным числом, заставляя генерировать почти одинаковые числа.
Просто делать

Тогда есть распределения. Они работают, определяя диапазон, в котором вы хотите генерировать числа. Они легкие, хранят только пару цифр. В вашем случае вам нужно 2 из них. Один для распределения координат x и один для координат y (если они не отличаются, вам нужна только одна, потому что они будут определять один и тот же диапазон).

Вы генерируете числа, передавая генератор через распределение, как если бы вы использовали функцию.

Теперь вы хотите создать более одной позиции.
Генерация координат остается прежней, но вы должны сделать это внутри цикла. В своем первом коде вы генерируете одну позицию и используете ее дважды, в результате чего два врага размещаются в одном месте. Просто включите поколение внутри цикла.

Источник

Новые генераторы случайных чисел(ГСЧ) из С++11

Вступление

Но мы ведь пишем на плюсах. В 11 стандарте С++ для программистов предоставляются обширные возможности для создания ГЧ и их использования. Надо отметить, что ничего нового не придумали, а добавили классы из библиотеки boost (boost/random). Так что для тех, кто не может пользоваться свежим компилятором, всегда есть вариант с использованием данной библиотеки.

В связи с чем возникла потребность новых ГСЧ? Если вы пишите проекты чуть более сложные, чем Hello World, то «случайности» ГСЧ (а правильнее ГПСЧ) srand вам попросту не хватит, несложно будет вычислить порядок следования последовательности, и вызов будет происходить в одно и то же время, давая одинаковый результат. Также, само по себе использование srand неудобно, все хорошо лишь при диапазоне от 0 до n, вдобавок n ограничен потолком short int на некоторых системах. А если надо брать нижнюю границу, отличную от 0, то появляются лишние числа, вычисления, влекущие ошибки, связанные с неверным подсчетом. Еще хуже дело обстоит с генерацией СЧ в виде числа с плавающей точкой. И рассмотренные ниже классы помогут нам в этом нелегком пути. Пусть вас не пугают длинные непривычные названия, попробовав новый функционал, вы будете даже простые задачки решать с его помощью.

Знакомство с новым ГПСЧ

Мы будем использовать генератор mersenne twister, а точнее mt19937. Основанный на свойствах простых чисел, он подходит для решения большинства задач. Несмотря на то, что степень его «случайности» весьма неплоха, он все-таки является ГПСЧ. Генерирует СЧ он достаточно быстро и хватить его должно с головой.

Определен он, как и все, что мы далее будем рассматривать, в хедере random и пространстве имен std. Является 32-битным генератором, имеет собрата mt19937_64, являющегося 64-битным.
В конструкторе может инициализироваться величиной, от которой начинается генерация последовательности, либо специальным объектом seed_seq, являющимся зерном последовательности. Мы будем использовать первый вариант.

Пример: создание переменных std::mt19937

int main()
<
std::mt19937 gen1, gen2(time( 0 ));
>

В первом случае мы просто создаем объект, во втором, инициализируем его начальным значением. Пока все похоже на srand.
Класс имеет метод seed(), с помощью которого можно назначить зерно последовательности.

Пример: использование метода seed

int main()
<
std::mt19937 gen;
gen.seed(time( 0 ));
>

Здесь мы сначала создаем ГПСЧ, а потом задаем зерно (стартовое значение) его последовательности.

По вызову operator(), генератор производит число. Все как и с rand(), только теперь этим занимается один класс. Может иметь в качестве параметра распределение (переменная, отвечающая за диапазон значений). Очень удобно использовать даже один генератор и несколько разных распределений. О них мы поговорим далее, но сначала пример.

Пример: генерация СЧ и вывод на экран

#include
#include
#include

int main()
<
std::mt19937 gen;
gen.seed(time( 0 )); // try to comment this string
std::cout «My number: «

Распределения

Сами по себе, генераторы, конечно, незаменимы, но без возможности указания диапазона нужного значения они становятся лишь чуть лучше, чем srand. Я рассмотрю два основных распределения, но их существует гораздо большее количество, на все случаи жизни, так сказать.

Читайте также:  bny mellon акции что это

Все они принимают в качестве аргументов в конструкторе либо параметры другого распределения, либо переменные, отвечающие за диапазон значений. Если оные не указаны, то используется диапазон от 0 до максимального значения, определенного в numeric_limits<>::max() данного идентификатора типа, являющегося параметром шаблона.

Если указан лишь один аргумент, то берется диапазон значений от данного до максимального. Следует отметить, что границы также учитываются, т.е. при указании в качестве аргументов a, b используется диапазон [a, b].

Каждое распределение имеет след. методы и функции для работы с ними:
1) перегруженный конструктор, описанный выше
2) reset, отвечающее за сброс последовательности распределения
3) оператор (), про него подробнее расскажу ниже
4) деструктор
5) param, возвращающий параметры данного распределения. Используется для передачи параметров одного распределения другому.
6) max, возвращающий максимально возможное значение, возвращаемое оператором ()
7) min, возвращающий минимально возможное значение, возвращаемое оператором ()
8) a, возвращающий верхнюю границу параметра распределения
9) b, возвращающий нижнюю границу параметра распределения
10) также имеет перегруженные версии операторов >

Оператор () принимает в качестве параметра генератор и возвращает число из диапазона распределения. При этом на одно и то же распределение можно применять совершенно различные генераторы, отвечают они лишь за диапазон.

Все это мб сейчас для вас лишь непонятная скучная теория, но я постараюсь разбавить её примерами, на основе следующего распределения.

std::uniform_int_distribution

Применяется для указания диапазона целых чисел. Лучше всего подходит для int, unsigned int, long, unsigned long, long long, unsigned long long. Является шаблонным классом, по умолчанию использует int.

А теперь давайте по пунктам разберем методы.

Пример: создание ГПСЧ с разбросом от 0 до 50 и вывод на экран двух СЧ

#include
#include
#include

В этом примере используется перегруженная версия конструктора, принимающая два аргумента. Как видите, оператор() принимает в качестве параметра ГПСЧ и возвращает СЧ из данного диапазона.

Давайте теперь создадим распределение на основе данного и посмотрим их характеристики (мин. и макс. значения диапазона). Заодно научимся использовать методы max() и min().

Пример: передача параметров одного распределения в качестве аргументов другого

#include
#include
#include

Как видите, один ГПСЧ инициализируется параметрами другого, и их характеристики эквиваленты. Следует отметить, что методы min() и max() возвращают переменную по значению, а не по ссылке, поэтому если мы раскомментируем строчку вконце, то получим ошибку компиляции.

А для чего же тогда нужны методы a() и b()?
Они возвращают параметры распределения. a() вернет нижнюю границу, b() верхнюю. На самом деле, их можно использовать заместо методов min() и max(), обратное неверно. Но я бы рекомендовал все же отталкиваться от ситуации, а именно, использовать a() и b() лишь в качестве аргументов при передаче параметра распределения и max() и min() во всех остальных случаях, дабы не ломать себе, а еще хуже кому-нибудь, потом голову, а что же это за методы такие.

Пример: передача нижней границы одного распределения в качестве аргумента другого распределения

#include
#include
#include

Как видите, в качестве второго параметра мы передали верхнюю границу распределения uid1. Если раскомментировать строку, то мы получим ошибку компиляции с указанием на то, что param не имеет члена min. a() и b() также возвращают результат по значению, а не по ссылке, т.о. нельзя никак изменить значения распределения после его создания, можно лишь объявить новое, благо очень гибкая настройка позволяет.

Но и это еще не все. Благодаря перегруженным версиям операторов > мы можем вывести границы распределения и задать их прямо в output/с input потока.

Пример: задание параметров распределения с потока std::cin и вывод на экран

int main()
<
std::uniform_int_distribution uid;
std::cin >> uid;
std::cout

Сначала идет нижняя граница, потом верхняя. Сразу видна забота о программистах 🙂

Осталось лишь упомянуть о методе reset. Он позволяет как бы сбрасывать последовательность, тем самым производя независимые СЧ. Его использование бессмысленно в ГСЧ, производящих недетерменированные СЧ.

Если кто-то еще не понял, как работают распределения и каков принцип действия ГСЧ(ГПСЧ), ниже приведу подробный пример с комментариями

Пример: простая игра с угадыванием числа

#include
#include
#include

std::uniform_real_distribution

Применяется для указания диапазона действительных чисел. Лучше всего подходит для float, double, long double. Является шаблонным классом, по умолчанию использует double.

Похож на своего собрата, описанного выше, как две капли воды, за исключением того, что оперирует с числами с плавающей точкой, а не целыми. Имеет идентичный набор методов для работы.

Пример: использование распределения std::uniform_real_distribution

#include
#include
#include

Читайте также:  какой лучше брать водонагреватель проточный или накопительный

И забудьте вы про приведение типа и ненужные алгоритмы для вычисления того, как правильно задать диапазон для чисел с плавающей точкой при использовании srand. Все просто, удобно, лаконично.

Я рассмотрел 2 распределения. Всего их в стандарте 20! А в бусте и еще больше. Но эти основные и подойдут для решения стандартных задач.

std::random_device

Класс имеет методы min() и max(), а также entropy(), который возвращает любое ненулевое число в случае производства действительно СЧ, иначе вернет 0. Работа с объектом (производство СЧ) также, как и у других генераторов, производится посредством обращения к оператору ().

Пример: создание ГСЧ std::random_device

Иногда ГПСЧ инициализируют результатом действия ГСЧ (time(0) оказывается недостаточно).

Пример: инициализация ГПСЧ результатом работы ГСЧ

Первые две строчки из main можно заменить на запись

либо аналогичную, с помощью brace initialization

std::bind

Пример: использование std::bind для имитации бросания кости

#include
#include
#include

std::generate

Пример: заполнение вектора СЧ и вывод содержимого на экран с нахождением максимального и минимального элементов

Подведение итогов

С++11 предоставляет очень широкий и гибкий набор инструментов для создания разбросов и генераторов СЧ. Мы рассмотрели основные, а также работу с ними. Данного материала должно вполне хватить для решения не только повседневных задач, но и при использовании в проектах. Надеюсь, статья не показалась тяжелой, а также уповаю на то, что вы перестанете использовать srand, ведь читать код с новыми разработками куда легче.

Напоследок пример: рулетка с rm rf

#include
#include
#include

Литература

С уважением, mrgluck.

Если Вам понравилась статья, проголосуйте за нее

Голосов: 15 Голосовать

Источник

Функция рандома с использованием mt19937

Здравствуйте. Начал изучать C++, помогите пожалуйста разобраться с одним вопросом.

Экспериментирую сейчас с рандомом. Нужно создать функцию, которая выдает рандомное число с заданным диапазоном.
Это получилось сделать с помощью random_device:

Но как сделать тоже самое, но с помощью mt19937? Ибо подобный результат меня совсем не радует:

Как выглядит функция рандома?
как выглядит функция рандома? я видел код,но ничего понял

Функция рандома для int: Ожидался класс, делегат, перечисление или структура
Требуется помощь. Не могу понять, что я сделал неправильно, почему мне пишет, что ожидался класс.

Стоит ли использовать «Вихрь Мерсенна» (std::mt19937)?
Чем он отличается от «обычного» stdlib’ного ГПСЧ? Генерирует ли он более. качественные ПСЧ? И.

Функция с использованием массивов
Помогите написать функцию,которая вставляет элементы в монотонно возрастающую последовательность с.

Решение

По вашему мнению, стоит ли использовать именно mt19937, так как многие не рекомендуют часто использовать random_device, или нет особой разницы?

Функция с использованием указателей
В задании написать функцию, которая вычисляет выражение по вашему выражении. В функции.

Функция с использованием объединения
Используя объединение, написать функцию, записывающую в файл двоичное представление значения типа.

Функция вывода с использованием класса
Предположим, у меня есть класс прямоугольника Window; И я реализовал в нем функцию вывода void.

Функция с использованием статической переменной
Создать функцию с использованием статической переменной (или переменных), определенной на локальном.

функция Заменить с использованием макроса
Есть столбец со следующими значениями Картофель; Картофель Молодой. Причем в некоторых строчках.

Генератор рандома
Привет всем 🙂 В универе задали написать генератор случайных чисел, имеющий интерфейс для задания.

Источник

СОДЕРЖАНИЕ

заявка

Программное обеспечение

Mersenne Twister используется в качестве ГПСЧ по умолчанию в следующем программном обеспечении:

Преимущества

Недостатки

Альтернативы

Альтернативный генератор, WELL («Well Equidistributed Long-period Linear»), предлагает более быстрое восстановление, равную случайность и почти равную скорость.

Генераторы xorshift и их варианты Marsaglia являются самыми быстрыми в классе LFSR.

. Тогда каждая из 2 kv возможных комбинаций битов встречается одинаковое количество раз за период, за исключением комбинации всех нулей, которая встречается один раз реже.

Алгоритмическая деталь

Для w- битного слова Twister Мерсенна генерирует целые числа в диапазоне [0, 2 w −1].

Общий алгоритм характеризуется следующими величинами (некоторые из этих объяснений имеют смысл только после прочтения остальной части алгоритма):

Коэффициенты для MT19937:

Коэффициенты для MT19937-64:

Инициализация

Состояние, необходимое для реализации Mersenne Twister, представляет собой массив из n значений по w бит каждое. Для инициализации массива используется w- битное начальное значение для предоставления от x 0 до x n −1 путем установки x 0 на начальное значение и последующей установки

Сравнение с классической GFSR

Преобразование скручивания улучшает классический GFSR со следующими ключевыми свойствами:

Псевдокод

Варианты

CryptMT

TinyMT

Источник

Как кратко, портативно и тщательно посеять PRNG mt19937?

Кажется, я вижу много ответов, в которых кто-то предлагает использовать генерировать случайные числа, обычно вместе с кодом, подобным этому:

Обычно это заменяет некую «нечестивую мерзость», такую ​​как:

Мы можем критиковать старый способ, утверждая, что time(NULL) обеспечивает низкую энтропию, time(NULL) предсказуемо, и конечный результат неоднороден.

Читайте также:  какой объем двигателя у волги 3110

Но все это верно для нового пути: у него просто блестящий шпон.

С помощью std::mt19937 gen(rd());gen() (заполнение 32 битами и просмотр первого вывода) не дает хорошего распределения вывода. 7 и 13 никогда не могут быть первым выходом. Два семени дают 0. Двенадцать семян дают 1226181350. (Ссылка на сайт )

Хуже того, очень легко скопировать и вставить вышеприведенные фрагменты кода, несмотря на проблемы, которые они содержат. Некоторые решения этого требуют приобретения великоватый библиотеки который не может быть подходящим для всех.

В свете этого мой вопрос Как можно лаконично, переносимо и тщательно запустить PRNG mt19937 в C ++?

Учитывая вышеперечисленные вопросы, хороший ответ:

мысли

std::random_device::entropy() не дать хорошее представление о том, что std::random_device может или не может сделать.

Решение

То есть нет полностью портативный Решение: однако, есть достойный, минимальный подход. Вы можете использовать минимальную оболочку вокруг CSPRNG (определяется как sysrandom ниже), чтобы посеять PRNG.

Windows

Вы можете положиться на CryptGenRandom CSPRNG. Например, вы можете использовать следующий код:

Unix-Like

На многих Unix-подобных системах вы должны использовать / DEV / urandom когда это возможно (хотя это не гарантируется в POSIX-совместимых системах).

Другой

засеивание

Теперь, когда у нас есть кусочки с минимальными издержками, мы можем сгенерировать нужные биты случайной энтропии для заполнения нашего PRNG. В примере используются (очевидно, недостаточно) 32-битные значения для заполнения PRNG, и вам следует увеличить это значение (которое зависит от вашего CSPRNG).

Сравнение для повышения

Linux Специализация

OpenBSD

другие мысли

Если вам нужны криптографически безопасные случайные байты, вам, вероятно, следует заменить fstream небуферизованным открытием / чтением / закрытием POSIX. Это потому, что оба basic_filebuf а также FILE содержит внутренний буфер, который будет выделяться через стандартный распределитель (и, следовательно, не стирается из памяти).

Это можно легко сделать, изменив sysrandom чтобы:

Спасибо

Отдельное спасибо Бену Фойгту за указание FILE использует буферизованные чтения и поэтому не должен использоваться.

Другие решения

В некотором смысле это нельзя сделать переносимым. То есть можно представить действительную полностью детерминированную платформу, работающую на C ++ (скажем, симулятор, который детерминирует тактовые импульсы машины и с «детерминированным» вводом / выводом), в котором нет источника случайности для заполнения PRNG.

Вы можете использовать std::seed_seq и заполните его, по крайней мере, до требуемого размера состояния генератора, используя метод получения энтропии Александра Хуссага:

Если был правильный способ заполнить или создать SeedSequence из UniformRandomBitGenerator в стандартной библиотеке с помощью std::random_device для посева правильно было бы намного проще.

Реализация, над которой я работаю, использует преимущества state_size собственность mt19937 PRNG решает, сколько семян предоставить при инициализации:

Я думаю, что есть возможности для улучшения, потому что std::random_device::result_type может отличаться от std::mt19937::result_type по размеру и диапазону, так что это действительно должно быть принято во внимание.

Согласно C++11(/14/17) стандарт (ы):

26.5.6 Класс random_device [ rand.device ]

2 Если ограничения реализации не позволяют генерировать недетерминированные случайные числа, реализация может использовать механизм случайных чисел.

Это означает, что реализация может генерировать только детерминистический значения, если это не позволяет генерировать недетерминирована по некоторым ограничениям.

MinGW компилятор на Windows лихо не обеспечивает недетерминирована значения из его std::random_device несмотря на то, что они легко доступны из операционной системы. Поэтому я считаю, что это ошибка, которая вряд ли встречается в разных реализациях и платформах.

Нет ничего плохого в посеве с использованием времени, если вам не нужно, чтобы оно было безопасным (и вы не сказали, что это было необходимо). Суть в том, что вы можете использовать хеширование, чтобы исправить неслучайность. Я нашел, что это работает адекватно во всех случаях, в том числе, в частности, для тяжелых моделей Монте-Карло.

Одна приятная особенность этого подхода заключается в том, что он обобщается на инициализацию из других не совсем случайных наборов семян. Например, если вы хотите, чтобы каждый поток имел свой собственный ГСЧ (для обеспечения безопасности потока), вы можете просто инициализировать его на основе хешированного идентификатора потока.

Вот мой собственный ответ на вопрос:

Идея здесь состоит в том, чтобы использовать XOR для объединения многих потенциальных источников энтропии (быстрое время, медленное время, std::random-device расположение статических переменных, расположение кучи, расположение функций, расположение библиотеки, значения, специфичные для программы), чтобы предпринять максимальную попытку инициализации mt19937. Пока хотя бы один источник будет «хорошим», результат будет по крайней мере таким «хорошим».

Этот ответ не такой короткий, как хотелось бы, и может содержать одну или несколько логических ошибок. Так что я считаю, что это в стадии разработки. Пожалуйста, прокомментируйте, если у вас есть отзывы.

Я ранее использовал что-то вроде (uint64_t)( time(NULL)*CLOCKS_PER_SEC + clock() ) получить больше битов энтропии для приложений, не критичных к безопасности.

Источник

Сказочный портал