Генерировать случайные числа в указанном диапазоне в C++
В этом посте будет обсуждаться, как генерировать случайные числа в указанном диапазоне в C++.
1. Использование std::uniform_int_distribution
Простое решение для создания случайных чисел между двумя значениями (включительно) в современном C++ использует std::uniform_int_distribution , который генерирует случайные целые значения, равномерно распределенные на указанном закрытом интервале.
Следующее решение производит высококачественные целые случайные числа в заданном закрытом интервале с std::uniform_int_distribution . Оно использует std::random_device получить сид для стандартного mersenne_twister_engine std::mt19937 , основанный на алгоритме Mersenne Twister.
std:: uniform_int_distribution
Random number distribution that produces integer values according to a uniform discrete distribution, which is described by the following probability mass function:
This distribution produces random integers in a range [a,b] where each possible value has an equal likelihood of being produced. This is the distribution function that appears on many trivial random processes (like the result of rolling a die).
The distribution parameters, a and b, are set on construction.
To produce a random value following this distribution, call its member function operator().
For a discrete distribution that can have different probabilities for each possible value, see discrete_distribution.
Template parameters
Member types
The following aliases are member types of uniform_int_distribution:
9.5 – Генерирование случайных чисел
Возможность генерировать случайные числа может быть полезна в определенных видах программ, особенно в играх, программах статистического моделирования и научных симуляторах, которые должны моделировать случайные события. Возьмем, к примеру, игры – без случайных событий монстры всегда будут атаковать вас одинаково, вы всегда найдете одно и то же сокровище, расположение подземелий никогда не изменится и т.д. И это не сделает игру очень хорошей.
Так как же нам генерировать случайные числа? В реальной жизни мы часто получаем случайные результаты, например, подбрасывая монету, бросая кости или тасуя колоду карт. Эти события включают в себя так много физических переменных (например, гравитацию, трение, сопротивление воздуха, импульс и т.д.), что их почти невозможно предсказать или контролировать, и они дают результаты, которые во всех смыслах случайны.
Однако компьютеры не предназначены для использования преимуществ физических переменных – ваш компьютер не может подбрасывать монету, бросать кости или тасовать реальные карты. Компьютеры живут в управляемом электрическом мире, где всё двоично (ложь или истина) и нет промежуточного состояния. По самой своей природе компьютеры предназначены для получения максимально предсказуемых результатов. Когда вы говорите компьютеру вычислить 2 + 2, вы всегда хотите, чтобы ответ был 4. А не 3 или 5 в отдельных случаях.
Следовательно, компьютеры обычно не способны генерировать случайные числа. Вместо этого они должны моделировать случайность, что чаще всего делается с помощью генераторов псевдослучайных чисел.
Генератор псевдослучайных чисел (ГПСЧ или PRNG, pseudo-random number generator) – это программа, которая принимает начальное число (англ. seed) и выполняет над ним математические операции, чтобы преобразовать его в какое-то другое число, которое, кажется, не связано с начальным числом. Затем он берет это сгенерированное число и выполняет с ним ту же математическую операцию, чтобы преобразовать его в новое число, не связанное с числом, из которого оно было сгенерировано. Постоянно применяя алгоритм к последнему сгенерированному числу, он может генерировать последовательность новых чисел, которые будут казаться случайными, если алгоритм достаточно сложен.
Лучшая практика
Предоставить начальное значение своему генератору случайных чисел вы должны только один раз. Если ввести его более одного раза, результаты будут менее случайными или совсем не случайными.
На самом деле написать ГПСЧ довольно просто. Вот короткая программа, которая генерирует 100 псевдослучайных чисел:
Результат этой программы:
Каждое число кажется довольно случайным по сравнению с предыдущим. Как оказалось, наш алгоритм на самом деле не очень хорош по причинам, которые мы обсудим позже. Но он эффективно иллюстрирует принцип генерации значений генератором псевдослучайных чисел.
Генерация случайных чисел в C++
C (и, как следствие, C++) поставляется со встроенным генератором псевдослучайных чисел. Он реализован как две отдельные функции, которые находятся в заголовке cstdlib :
std::srand() устанавливает начальное порождающее значение в значение, которое передается вызывающей функцией. std::srand() необходимо вызывать только один раз, в начале вашей программы. Обычно это делается в верхней части main() .
std::rand() генерирует следующее случайное число в последовательности. Это число будет псевдослучайным целым числом от 0 до RAND_MAX , значение константы в cstdlib , которое обычно установлена на 32767.
Вот пример программы, использующей эти функции:
Вот результат этой программы:
Последовательности ГПСЧ и заполнение
Если вы запустите приведенный выше пример программы с std::rand() несколько раз, вы заметите, что она каждый раз выводит один и тот же результат! Это означает, что хотя каждое число в последовательности кажется случайным по сравнению с предыдущими, вся последовательность вовсе не случайна! А это означает, что наша программа оказывается полностью предсказуемой (одни и те же входные данные всегда приводят к одним и тем же выходным данным). Бывают случаи, когда это может быть полезно или даже желательно (например, вы хотите, чтобы научное моделирование повторялось, или вы пытаетесь выяснить, почему ваш генератор случайных подземелий дает сбой).
Но часто это не то, что нужно. Если вы пишете игру «hi-lo» (высоко-низко) (где у пользователя есть 10 попыток угадать число, а компьютер сообщает ему, является ли его предположение слишком высоким или слишком низким), вы не хотите, чтобы программа каждый раз выбирала одни и те же числа. Итак, давайте подробнее посмотрим, почему это происходит, и как мы можем это исправить.
Помните, что каждое число в последовательности ГПСЧ определенным образом генерируется из предыдущего числа. Таким образом, при любом одном и том же начальном числе ГПСЧ всегда будут генерировать одну и ту же последовательность чисел! Мы получаем ту же последовательность, потому что наше начальное число всегда 5323.
Чтобы сделать всю нашу последовательность случайной, нам нужен способ выбрать начальное число, которое не является фиксированным значением. Первый ответ, который, вероятно, приходит в голову, – нам нужно случайное число! Это хорошая мысль, но если нам нужно случайное число для генерации случайных чисел, тогда мы попадаем в уловку-22. Оказывается, нам на самом деле не нужно, чтобы наше начальное число было случайным – нам просто нужно выбирать что-то, что меняется при каждом запуске программы. Затем мы можем использовать наш ГПСЧ для генерации уникальной последовательности псевдослучайных чисел из этого начального числа.
Общепринятым методом для этого является использование системных часов. Каждый раз, когда пользователь запускает программу, время будет другим. Если мы используем это значение времени в качестве начального числа, тогда наша программа при каждом запуске будет генерировать другую последовательность чисел!
C поставляется с функцией std::time() , которая возвращает количество секунд с полуночи 1 января 1970 года. Чтобы использовать ее, нам просто нужно включить заголовок ctime , а затем инициализировать std::srand() с помощью вызов std::time(nullptr) . Мы еще не рассмотрели nullptr , но в данном контексте это эквивалент 0.
Вот та же программа, что и выше, но с вызовом time() в качестве начального числа:
Теперь наша программа будет каждый раз генерировать новую последовательность случайных чисел! Запустите ее пару раз и убедитесь сами.
Генерация случайных чисел между двумя произвольными значениями
Как правило, нам не нужны случайные числа от 0 до RAND_MAX – нам нужны числа между двумя другими значениями, которые мы назовем min и max . Например, если мы пытаемся имитировать, как пользователь бросает кубик, нам нужны случайные числа от 1 до 6.
Вот короткая функция, которая преобразует результат rand() в нужный диапазон:
Чтобы смоделировать бросок кубика, мы должны вызвать getRandomNumber(1, 6) . Чтобы выбрать случайную цифру, мы вызываем getRandomNumber(0, 9) .
Дополнительный материал: как работает предыдущая функция?
Функция getRandomNumber() может показаться немного сложной, но всё не так уж плохо.
Вернемся к нашей цели. Функция rand() возвращает число от 0 до RAND_MAX (включительно). Мы хотим каким-то образом преобразовать результат rand() в число от min до max (включительно). Это означает, что когда мы выполняем преобразование, 0 должен стать min , а RAND_MAX должен стать max с равномерным распределением чисел между ними.
Мы делаем это в пять этапов:
- Умножаем наш результат от std::rand() на дробь fraction . Это преобразует результат rand() в число с плавающей запятой от 0 (включительно) до 1 (не включая).
- Если rand() возвращает 0, тогда 0 * fraction по-прежнему равно 0. Если rand() возвращает RAND_MAX , тогда RAND_MAX * fraction равно RAND_MAX / (RAND_MAX + 1) , что немного меньше 1. Любые другие числа, возвращаемые функцией rand() будут равномерно распределены между этими двумя точками.
- Затем нам нужно знать, сколько чисел мы можем вернуть. Другими словами, сколько чисел находится между min (включительно) и max (включительно)?
- Это просто ( max — min + 1 ). Например, если max = 8 и min = 5, ( max — min + 1) = (8 — 5 + 1) = 4. Между 5 и 8 есть 4 числа (то есть 5, 6, 7 и 8).
- Умножаем два предыдущих результата вместе. Если у нас было число с плавающей запятой от 0 (включительно) до 1 (не включая), а затем мы умножили его на ( max — min + 1 ), теперь у нас есть число с плавающей запятой между 0 (включительно) и ( max — min + 1 ) (не включая).
- Преобразуем предыдущий результат в целое число. Это удаляет любую дробную составляющую, оставляя нам целочисленный результат от 0 (включительно) до ( max — min ) (включительно).
- Наконец, мы добавляем min , что переводит наш результат в целое число от min (включительно) до max (включительно).
Дополнительный материал: почему в предыдущей функции мы не используем оператор остатка от деления ( % )?
Один из наиболее частых вопросов, которые задают читатели, – почему мы используем деление в приведенной выше функции вместо взятия остатка от деления ( % ). Короткий ответ заключается в том, что метод с остатком от деления имеет тенденцию смещаться в пользу малых чисел.
Давайте посмотрим, что бы произошло, если бы вместо этого приведенная выше функция выглядела так:
Похожа, правда? Давайте разберемся, где всё идет не по плану. Чтобы упростить пример, скажем, что rand() всегда возвращает случайное число от 0 до 9 (включительно). В нашем примере мы выберем min = 0 и max = 6. Таким образом, max — min + 1 равно 7.
Теперь давайте посчитаем все возможные исходы:
Посмотрите на распределение результатов. Результаты с 0 по 2 появляются дважды, а с 3 по 6 – только один раз. Этот метод имеет явный уклон в сторону низких результатов. Экстраполируя это: большинство случаев, связанных с этим алгоритмом, будут вести себя аналогичным образом.
Теперь давайте посмотрим на результат функции getRandomNumber() выше, используя те же параметры, что и выше ( rand() возвращает число от 0 до 9 (включительно), min = 0 и max = 6). В этом случае fraction = 1 / (9 + 1) = 0,1. max — min + 1 по-прежнему 7.
Расчет всех возможных исходов:
Здесь всё еще есть небольшое смещение в сторону меньших чисел (0, 2 и 4 появляются дважды, тогда как 1, 3, 5 и 6 появляются один раз), но результаты распределены гораздо более равномерно.
Несмотря на то, что getRandomNumber() немного сложнее для понимания, чем альтернатива с остатком от деления, мы выступаем за метод с делением, потому что он дает менее предсказуемый результат.
Что такое хороший генератор псевдослучайных чисел?
Как я уже упоминал выше, ГПСЧ, который мы написали, не очень хороший. В этом разделе мы обсудим причины, почему. Это дополнительный материал, потому что он не имеет прямого отношения к C или C++, но если вам нравится программировать, вам, вероятно, всё равно будет интересно.
Чтобы быть хорошим, ГПСЧ должен обладать рядом свойств:
Во-первых, ГПСЧ должен генерировать каждое число примерно с одинаковой вероятностью. Это называется равномерностью распределения. Если одни числа генерируются чаще других, результат программы, использующей ГПСЧ, будет искажен!
Например, предположим, вы пытаетесь написать генератор случайных предметов для игры. Вы выбираете случайное число от 1 до 10, и если результат равен 10, с монстра выпадет мощный предмет вместо обычного. Вы ожидаете, что это произойдет с вероятностью 1 из 10. Но если результаты простого ГПСЧ распределены неравномерно, и он генерирует намного больше десяток, чем должен, ваши игроки в конечном итоге получат больше редких предметов, чем вы предполагали, что, возможно, упростит вашу игру.
Создание ГПСЧ, дающих равномерно распределенные результаты, является сложной задачей, и это одна из основных причин, по которой ГПСЧ, который мы написали в начале этого урока, не очень хороший.
Во-вторых, метод, с помощью которого генерируется следующее число в последовательности, не должен быть очевидным или предсказуемым. Например, рассмотрим следующий алгоритм ГПСЧ: число = число + 1 . Результаты этого ГПСЧ идеально равномерно распределены, но они не очень полезны в качестве последовательности случайных чисел!
В-третьих, ГПСЧ должен иметь хорошее пространственное распределение чисел. Это означает, что он должен возвращать низкие, средние и высокие значения, казалось бы, случайным образом. ГПСЧ, который вернул все низкие значения, а затем все высокие значения, может быть равномерно распределенным и непредсказуемыми, но он всё равно приведет к смещенным результатам, особенно если количество случайных чисел, которые вы реально используете, невелико.
В-четвертых, все ГПСЧ являются периодическими, что означает, что в какой-то момент сгенерированная последовательность чисел начнет повторяться. Длина последовательности до того, как ГПСЧ начинает повторяться, называется периодом.
Например, вот первые 100 чисел, сгенерированных из ГПСЧ с плохой периодичностью:
Вы можете заметить, что он сгенерировал 9 как второе число и снова 9 как 16-е число. ГПСЧ застревает, постоянно генерируя последовательность между этими двумя девятками: 9-130-97-64-31-152-119-86-53-20-141-108-75-42- (повтор).
Это происходит потому, что ГПСЧ детерминированы – при некотором наборе входных значений они каждый раз будут выдавать одно и то же выходное значение. Это означает, что как только ГПСЧ встречает набор входных данных, которые он использовал ранее, он начинает производить ту же последовательность выходных данных, которую он создавал раньше, что приводит к циклу.
Хороший ГПСЧ должен иметь длительный период для всех начальных значений. Разработка алгоритма, отвечающего этому свойству, может быть чрезвычайно сложной задачей – большинство ГПСЧ будут иметь длительные периоды для одних начальных значений и короткие периоды для других. Если пользователь выберет начальное число с коротким периодом, тогда ГПСЧ не будет работать хорошо.
Несмотря на сложность разработки алгоритмов, отвечающих всем этим критериям, в этой области было проведено множество исследований из-за ее важности для научных вычислений.
std::rand() – посредственный ГПСЧ
Алгоритм, используемый для реализации std::rand() , может варьироваться от компилятора к компилятору, что приводит к результатам, которые могут не совпадать между компиляторами. В большинстве реализаций rand() используется метод, называемый линейным конгруэнтным генератором (LCG, Linear Congruential Generator). Если вы посмотрите на первый пример в этом уроке, вы заметите, что на самом деле это LCG, хотя и с намеренно выбранными плохими константами. LCG, как правило, имеют недостатки, из-за которых они не подходят для решения большинства проблем.
Одним из основных недостатков rand() является то, что RAND_MAX обычно устанавливается равным 32767 (по сути, 15 бит). Это означает, что если вы хотите генерировать числа в большем диапазоне (например, 32-битные целые числа), rand() не подходит. Кроме того, rand() не подходит, если вы хотите генерировать случайные числа с плавающей запятой (например, от 0,0 до 1,0), что часто бывает полезно при статистическом моделировании. Наконец, rand() имеет относительно короткий период по сравнению с другими алгоритмами.
Тем не менее, rand() идеально подходит для обучения программированию и для программ, в которых высококачественный ГПСЧ не является необходимостью.
Для приложений, где полезен высококачественный ГПСЧ, я бы порекомендовал вихрь Мерсенна (Mersenne Twister) (или один из его вариантов), который дает отличные результаты и относительно прост в использовании. Вихрь Мерсенна был введен в C++11, и мы покажем, как его использовать позже в этом уроке.
Отладка программ, использующих случайные числа
Программы, использующие случайные числа, может быть трудно отлаживать, потому что программа при каждом запуске может вести себя по-разному. Иногда это может сработать, а иногда нет. При отладке полезно следить за тем, чтобы ваша программа каждый раз выполняла один и тот же (неправильный) путь. Таким образом, вы можете запускать программу столько раз, сколько необходимо, чтобы определить причину ошибки.
По этой причине при отладке полезно установить случайное начальное число (через std::srand ) на определенное значение (например, 0), которое вызывает ошибочное поведение. Это гарантирует, что ваша программа каждый раз будет генерировать одни и те же результаты, что упростит отладку. Как только вы обнаружите ошибку, вы можете снова использовать системные часы, чтобы снова начать генерировать рандомизированные результаты.
Получение лучших случайных чисел с помощью вихря Мерсенна
В C++11 в стандартную библиотеку C++ добавлено множество функций генерации случайных чисел, включая алгоритм вихря Мерсенна, а также генераторы для различных типов случайных распределений (равномерного, нормального, пуассоновского и т.д.). Доступ к нему осуществляется через заголовок <random> .
Вот небольшой пример, показывающий, как сгенерировать случайные числа в C++11 с помощью вихря Мерсенна:
Примечание автора
До C++17 вам нужно было после типа добавить пустые скобки для создания die
std::uniform_int_distribution<> die
Вы можете заметить, что вихрь Мерсенна генерирует случайные 32-битные целочисленные значения без знака (а не 15-битные целочисленные значения, как std::rand() ), что дает гораздо больший диапазон. Также существует версия ( std::mt19937_64 ) для генерации 64-битных целочисленных значений без знака.
Случайные числа в нескольких функциях
В приведенном выше примере генератор псевдослучайных чисел создается для использования в одной функции. Что произойдет, если мы захотим использовать генератор случайных чисел в нескольких функциях?
Хотя вы можете создать статическую локальную переменную std::mt19937 в каждой функции, которая в ней нуждается (статическая, чтобы она была инициализирована только один раз); но это немного излишне – чтобы каждая функция получала начальное значение для генератора случайных чисел и поддерживала свой собственный локальный генератор. В большинстве случаев лучшим вариантом является создание глобального генератора случайных чисел (внутри пространства имен!). Помните, как мы говорили вам избегать неконстантных глобальных переменных? Это исключение (также обратите внимание: std::rand() и std::srand() обращаются к глобальному объекту, поэтому для этого есть прецедент).
Использование библиотеки генерирования случайных чисел
Возможно, лучшее решение – использовать стороннюю библиотеку, которая обрабатывает всё это за вас, например, библиотеку генерирования случайных чисел Effolkronium, использующую только заголовочные файлы. Вы просто добавляете заголовочный файл в свой проект, включаете его с помощью #include , после чего можете начать генерировать случайные числа с помощью Random::get(min, max) .
Вот приведенная выше программа, модифицированная под использование библиотеки Effolkronium:
Помогите! Мой генератор случайных чисел генерирует одну и ту же последовательность случайных чисел!
Если ваш генератор случайных чисел при каждом запуске вашей программы генерирует одну и ту же последовательность случайных чисел, вы, вероятно, неправильно его инициализировали. Убедитесь, что вы инициализируете его значением, которое изменяется при каждом запуске программы (например, std::time(nullptr) ).
Помогите! Мой генератор случайных чисел всегда генерирует одно и то же первое число!
Реализация rand() в Visual Studio и некоторых других компиляторах имеет недостаток – первое сгенерированное случайное число не сильно меняется для похожих начальных значений. Это означает, что при использовании std::time(nullptr) для инициализации вашего генератора случайных чисел первый результат rand() не сильно изменится при последующих запусках. Однако на результаты последующих вызовов rand() это не повлияет, и они будут достаточно рандомизированы.
Решение здесь, и хорошее практическое правило в целом, – отбросить первое число, сгенерированное генератором случайных чисел.
Помогите! Мой генератор случайных чисел вообще не генерирует случайные числа!
Если ваш генератор случайных чисел генерирует одно и то же число каждый раз, когда вы запрашиваете случайное число, то вы, вероятно, либо повторно инициализируете генератор случайных чисел перед генерацией случайного числа, либо создаете новый генератор случайных чисел для каждого получения случайного числа.
Вот две функции, которые показывают проблему:
В обоих случаях генератор случайных чисел инициализируется перед каждой генерацией случайного числа. Это приведет к тому, что каждый раз будет генерироваться одно и то же число.
В верхнем случае std::srand() повторно инициализирует встроенный генератор случайных чисел перед вызовом rand() (с помощью getRandomNumber() ).
В нижнем случае мы создаем новый вихрь Мерсенна, инициализируем его, генерируем одно случайное число и затем уничтожаем его.
Для получения случайных результатов вы должны инициализировать генератор случайных чисел только один раз (обычно при инициализации программы для std::srand() или в точке создания для других генераторов случайных чисел), а затем использовать тот же генератор случайных чисел для каждого последующего генерируемого случайного числа.
Предупреждение
Пример getOtherRandomNumber() – одна из самых распространенных ошибок, которые допускаются в тестах. Вы не заметите, что getOtherRandomNumber() не работает, пока вы не начнете вызывать его чаще, чем один раз в секунду (поскольку начальное число изменяется только один раз в секунду). Не забудьте сделать генератор случайных чисел статическим или объявить его вне функции.
Заполнить массив случайными числами в C++
Программирование и разработка
Заполнение массива случайными числами звучит просто, если предположить, что массив состоит из 10 элементов. Для этого сгенерируйте случайное число и поместите его в массив в качестве первого элемента. Сгенерируйте еще одно случайное число и вставьте его в качестве второго элемента. Затем снова сгенерируйте третье случайное число и введите его в качестве третьего элемента. Продолжайте таким образом, пока не будет достигнут десятый элемент.
Тем не менее, есть и другие вещи, на которые следует обратить внимание, прежде чем кодировать это. Случайные числа, сгенерированные C++20, следуют определенной последовательности. Таких последовательностей много, поэтому случайные числа не являются действительно случайными. Пользователь программы вряд ли сможет узнать, какую последовательность выбрал программист и как определить следующее число при вызове случайной функции в том же коде.
Каждая последовательность имеет начальный номер. Семя связано с начальным номером последовательности. Каждая последовательность зависит от начального числа и распределения последовательности. Распределение последовательности является профилем последовательности.
В этой статье объясняется, как заполнить массив случайными числами, начиная с классов: random_device, default_random_engine и uniform_int_distribution. Все эти классы находятся в случайной библиотеке, которую необходимо включить. Скелет программы для заполнения массива из 10 элементов случайными числами выглядит следующим образом:
#include <iostream>
#include <random>
using namespace std ;int arr [ 10 ] ;
int main ( )
<
//statements
return 0 ;
>
Обратите внимание, что любой арифметический тип может быть использован в качестве типа элемента для массива. Размер массива равен 10. Однако можно получить любое количество случайных чисел.
Engine и Distribution
В этой теме движок — это генератор случайных чисел.
random_device
Это класс, из которого создаются экземпляры объектов. Объект этого класса — это устройство, а не двигатель. Это нуждается в генераторе, чтобы быть полезным. Генератор может принимать в качестве аргумента random_device.
default_random_engine
Движок в этой теме генерирует случайные числа. Существуют разные движки, из которых программист может выбирать. Это нужно выбирать, когда программист не уверен, какой движок выбрать. Это класс, из которого создаются экземпляры объектов. Он принимает объект random_device в качестве аргумента.
uniform_int_distribution
Программист может выбирать из множества профилей распределения последовательностей. Для этой статьи выбрано:uniform_int_distribution. Это класс, из которого можно создавать объекты. Его конструкция использует в качестве аргумента движок, а также нижний и верхний предельные числа для случайных чисел. На самом деле это шаблон класса. Один из его синтаксисов конструкции:
explicit uniform_int_distribution ( IntType a , IntType b = numeric_limits < IntType >:: max ( ) ) ;
Следующие три утверждения работают вместе:
random_device rd ;
default_random_engine eng ( rd ( ) ) ;
uniform_int_distribution < int > dist ( 4 , 13 ) ;
От 4 до 13 — десять целых чисел, включая нижний и верхний пределы. Специализация шаблона для объекта распределения dist — int. Таким образом, из этого диапазона можно выбрать десять различных случайных чисел (4–13). Обратите внимание, что аргументом для eng() является rd(), а не rd. Также обратите внимание, что любой арифметический тип может быть специализацией шаблона для этой конструкции распределения.
Из этого кода для получения следующего случайного числа используйте «dist(eng);».
Создание десяти случайных целых чисел
Следующая программа выдает десять случайных целых чисел от 4 до 13 включительно.
Вывод с компьютера автора:
Некоторые числа встречались более одного раза. Программа начинается с включения библиотеки iostream для ввода и вывода. После этого включается случайная библиотека для случайных чисел. Следующая строка является оператором, а не директивой. Заканчивается точкой с запятой. Он настаивает на том, чтобы любое имя, которому не предшествует «std::», принадлежало стандартному пространству имен.
Затем идет основная функция С++. Первые три утверждения функции main были объяснены ранее. В следующем сегменте кода dist(eng) выводит следующее случайное число; разумеется, в пределах диапазона (включительно), заданного в качестве аргументов конструктору дистрибутива.
Заполнение массива случайными числами
В приведенном выше коде было создано десять случайных чисел с помощью выражения dist(eng). Это было напечатано десять раз. Его можно ввести один раз и вызвать десять раз, если это делается в цикле for. Цикл for должен повториться десять раз. В этой ситуации возвращаемое случайное число не будет отправлено на терминал (экран); он будет отправлен в следующее местоположение элемента массива. Следующая программа иллюстрирует это:
#include <iostream>
#include <random>
using namespace std ;
int arr [ 10 ] ;
int main ( )
<
random_devicerd ;
default_random_engineeng ( rd ( ) ) ;
uniform_int_distributiondist ( 4 , 13 ) ;for ( int i = 0 ; i < 10 ; i ++ )
arr [ i ] = dist ( eng ) ;for ( int i = 0 ; i < 10 ; i ++ )
cout << arr [ i ] << ‘ ‘ ;
cout << endl ;
return 0 ;
>
На этот раз вывод компьютера автора:
Обратите внимание, как был закодирован первый цикл for. Конечно, можно выбрать любой диапазон, следующая программа использует диапазон от 0 до 100:
#include <iostream>
#include <random>
using namespace std ;
int arr [ 10 ] ;
int main ( )
<
random_devicerd ;
default_random_engineeng ( rd ( ) ) ;
uniform_int_distributiondist ( 0 , 100 ) ;for ( int i = 0 ; i < 10 ; i ++ )
arr [ i ] = dist ( eng ) ;for ( int i = 0 ; i < 10 ; i ++ )
cout << arr [ i ] << ‘ ‘ ;
cout << endl ;
return 0 ;
>
На этот раз вывод компьютера автора:
Хотя диапазон содержит более десяти целых чисел, было получено только десять случайных чисел, как было определено первым циклом for.
Заключение
Выполните следующую процедуру, чтобы заполнить массив случайными числами: сгенерируйте случайное число и поместите его в массив в качестве первого элемента. Сгенерируйте еще одно случайное число и вставьте его в качестве второго элемента. Сгенерируйте третье случайное число и введите его в качестве третьего элемента. Продолжайте таким образом, пока не будет достигнуто необходимое количество случайных чисел. Следующий сегмент кода важен:
int arr [ 10 ] ;
random_device rd ;
default_random_engine eng ( rd ( ) ) ;
uniform_int_distribution < int > dist ( 0 , 100 ) ;
for ( int i = 0 ; i < 10 ; i ++ )
arr [ i ] = dist ( eng ) ;