<random>
Определяет средства для генерации случайных чисел с равномерным распределением.
#include <random>
Сводка
Генератор случайных чисел — это объект, формирующий последовательность из псевдослучайных чисел. Генератор, который получает значения с равномерным распределением в указанном диапазоне, называют равномерным генератором случайных чисел (РГСЧ). Класс шаблона, который работает как РГСЧ, называют механизмом, если этот класс обладает определенными характеристиками, которые описываются далее в этой статье. РГСЧ может объединяться и обычно объединяется с распределением за счет передачи РГСЧ в качестве аргумента operator() распределения для получения значений, распределенных в соответствии с заданным распределением.
Эти ссылки ведут к основным разделам статьи.
Примеры кода
Классифицированные списки
Механизмы и распределения
Примечания
Краткие советы
Вот несколько советов по использованию <random>.
В большинстве случаев РГСЧ формируют необработанные значения, которые упорядочиваются распределением. (Исключением служит функция std::shuffle(), так как она использует РГСЧ напрямую.)
Один экземпляр РГСЧ или распределения не может безопасно вызываться параллельно, так как использование РГСЧ или распределения — это операция изменения. Для получения дополнительной информации см. Потокобезопасность в стандартной библиотеке C++.
Существуют предварительно заданные определения типов нескольких механизмов. Это рекомендуемый способ создания РГСЧ, если используется механизм.
Самое полезное сочетание для большинства приложений — это механизм mt19937 с uniform_int_distribution, как показано в примере кода далее в этой статье.
В заголовке можно выбрать различные варианты <random>; любой из них предпочтительнее устаревшей функции библиотеки времени выполнения C rand(). Сведения о недостатках rand() и о том, как <random> справляется с этими недостатками, см. в этом видео.
Примеры
В следующем примере кода показана генерация случайных чисел; в этом случае пять из них используют генератор, созданный с недетерминистическим начальным значением.
#include <random>
#include <iostream>
using namespace std;
int main()
{
random_device rd; // non-deterministic generator
mt19937 gen(rd()); // to seed mersenne twister.
// replace the call to rd() with a
// constant value to get repeatable
// results.
for (int i = 0; i < 5; ++i) {
cout << gen() << " "; // print the raw output of the generator.
}
cout << endl;
}
Результат
Это высококачественные случайные числа, они разные при каждом запуске этой программы, но не обязательно находятся в полезном диапазоне. Для управления диапазоном следует использовать однородное распределение, как показано в следующем коде:
#include <random>
#include <iostream>
using namespace std;
int main()
{
random_device rd; // non-deterministic generator
mt19937 gen(rd()); // to seed mersenne twister.
uniform_int_distribution<> dist(1,6); // distribute results between 1 and 6 inclusive.
for (int i = 0; i < 5; ++i) {
cout << dist(gen) << " "; // pass the generator to the distribution.
}
cout << endl;
}
Результат
В следующем примере кода показан более реалистичный набор случаев использования с однородно распределенными генераторами случайных чисел, перемешивающих содержимое векторов и массивов.
// cl.exe /EHsc /nologo /W4 /MTd
#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <string>
#include <vector>
#include <functional> // ref()
using namespace std;
template <typename C> void print(const C& c) {
for (const auto& e : c) {
cout << e << " ";
}
cout << endl;
}
template <class URNG>
void test(URNG& urng) {
// Uniform distribution used with a vector
// Distribution is [-5, 5] inclusive
uniform_int_distribution<int> dist(-5, 5);
vector<int> v;
for (int i = 0; i < 20; ++i) {
v.push_back(dist(urng));
}
cout << "Randomized vector: ";
print(v);
// Shuffle an array
// (Notice that shuffle() takes a URNG, not a distribution)
array<string, 26> arr = { { "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
"Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc",
"Ti", "V", "Cr", "Mn", "Fe" } };
shuffle(arr.begin(), arr.end(), urng);
cout << "Randomized array: ";
print(arr);
cout << "--" << endl;
}
int main()
{
// First run: non-seedable, non-deterministic URNG random_device
// Slower but crypto-secure and non-repeatable.
random_device rd;
cout << "Using random_device URNG:" << endl;
test(rd);
// Second run: simple integer seed, repeatable results
cout << "Using constant-seed mersenne twister URNG:" << endl;
mt19937 engine1(12345);
test(engine1);
// Third run: random_device as a seed, different each run
// (Desirable for most purposes)
cout << "Using non-deterministic-seed mersenne twister URNG:" << endl;
mt19937 engine2(rd());
test(engine2);
// Fourth run: "warm-up" sequence as a seed, different each run
// (Advanced uses, allows more than 32 bits of randomness)
cout << "Using non-deterministic-seed \"warm-up\" sequence mersenne twister URNG:" << endl;
array<unsigned int, mt19937::state_size> seed_data;
generate_n(seed_data.begin(), seed_data.size(), ref(rd));
seed_seq seq(begin(seed_data), end(seed_data));
mt19937 engine3(seq);
test(engine3);
}
Пример результатов и примечания к коду
Этот код показывает два разных метода рандомизации (вектора целых чисел и перемешивания массива индексированных данных) с помощью тестовой функции шаблона. В первом вызове тестовой функции используется криптобезопасный, недетерминистический, неповторяющийся РГСЧ random_device без начального значения. Во втором вызове в качестве РГСЧ используется mersenne_twister_engine с детерминистическим 32-разрядным постоянным начальным значением; это означает, что результаты повторяются. В третьем вызове для mersenne_twister_engine используется 32-разрядное недетерминистическое значение — результат выполнения random_device. В четвертом вызове применяется последовательность начальных значений, заполненная результатами выполнения random_device, что обеспечивает лучшую рандомизацию (но без криптобезопасности). Чтобы узнать больше, читайте дальше.
[в начало страницы]
Классифицированные списки
Равномерные генераторы случайных чисел
РГСЧ часто описываются следующими свойствами.
Длина периода: число итераций, необходимых для получения последовательности чисел. Чем период длиннее, тем лучше.
Производительность: сколько времени и памяти требуется для получения чисел. Чем меньше, тем лучше.
Качество: насколько полученная последовательность близка к реальным случайным числам. Часто это называется "стохастичностью".
В следующих разделах перечислены РГСЧ, доступные в заголовке <random>.
[в начало страницы]
Недетерминистический генератор
Формирует недетерминистическую, криптографическую безопасную случайную последовательность с помощью внешнего устройства. Обычно используется для получения начального значения для механизма случайных чисел. Низкая производительность, очень высокое качество. Дополнительные сведения см. в разделе Примечания. |
[в начало страницы]
Определения типа механизма с предварительно заданными параметрами
Для инициации механизмов и адаптеров. Дополнительные сведения см. в разделе Механизмы и распределения.
Имя |
Описание |
---|---|
default_random_engine |
Определение типа для механизма по умолчанию.
|
knuth_b |
Механизм Кнута.
|
minstd_rand0 |
Минимальный стандартный механизм 1988 (Льюис, Гудмэн и Миллер, 1969).
|
minstd_rand |
Обновленный минимальный стандартный механизм minstd_rand0 (Парк, Миллер и Стокмайер, 1993).
|
mt19937 |
32-разрядный механизм типа "Вихрь Мерсенна" (Матсумото и Нишимура, 1998).
|
mt19937_64 |
64-разрядный механизм типа "Вихрь Мерсенна" (Матсумото и Нишимура, 2000).
|
ranlux24 |
24-разрядный механизм RANLUX (Мартин Люшер и Фред Джеймс, 1994).
|
ranlux24_base |
Используется в качестве основания для ranlux24.
|
ranlux48 |
48-разрядный механизм RANLUX (Мартин Люшер и Фред Джеймс, 1994).
|
ranlux48_base |
Используется в качестве основания для ranlux48.
|
[в начало страницы]
Шаблоны механизмов
Шаблоны механизмов используются как автономные РГСЧ или базовые механизмы, которые передаются адаптерам механизмов. Обычно они инициализируются с предварительно заданным типом определения механизма и передаются в распределение. Дополнительные сведения см. в разделе Механизмы и распределения.
Создает случайную последовательность, используя линейный конгруэнтный алгоритм. Самый простой с самым низким качеством. |
|
Создает случайную последовательность, используя алгоритм "Вихрь Мерсенна". Самый сложный с самым высоким качеством (кроме класса random_device). Очень высокая производительность. |
|
Создает случайную последовательность, используя алгоритм вычитания с переносом. Улучшение linear_congruential_engine, но с более низким качеством и производительностью, чем у mersenne_twister_engine. |
[в начало страницы]
Шаблоны адаптеров механизмов
Адаптеры механизмов — это шаблоны, адаптирующие другие (базовые) механизмы. Обычно они инициализируются с предварительно заданным типом определения механизма и передаются в распределение. Дополнительные сведения см. в разделе Механизмы и распределения.
Создает случайную последовательность, удаляя значения, возвращенные базовым механизмом. |
|
Создает случайную последовательность с указанным числом разрядов, перемешивая разряды из значений, возвращенных базовым механизмом. |
|
Создает случайную последовательность, изменяя порядок значений, возвращенных базовым механизмом. |
[в начало раздела]
[в начало страницы]
Распределения случайных чисел
В следующих разделах перечислены распределения, доступные в заголовке <random>. Распределения — это механизмы постобработки, которые обычно используют результаты РГСЧ в качестве входа и распределяют выходные данные с помощью заданной функции плотности статистической вероятности. Дополнительные сведения см. в разделе Механизмы и распределения.
[в начало страницы]
Равномерные распределения
Формирует равномерное распределение целых чисел в диапазоне, заданном замкнутым интервалом [a, b] (a и b входят в диапазон). |
|
Формирует равномерное распределение вещественных чисел (с плавающей запятой) в диапазоне, заданном замкнутым интервалом [a, b) (a включено, b не входит в диапазон). |
|
Формирует равномерное распределение вещественных чисел (с плавающей запятой) с заданной точностью в диапазоне [0, 1) (0 входит в диапазон, 1 не входит). |
[в начало раздела]
Распределения Бернулли
Формирует распределение Бернулли значений типа bool. |
|
Формирует биномиальное распределение целых значений. |
|
Формирует геометрическое распределение целых значений. |
|
Формирует отрицательное биномиальное распределение целых значений. |
[в начало раздела]
Нормальные распределения
Формирует распределение Коши вещественных значений (с плавающей запятой). |
|
Формирует распределение хи-квадрат вещественных значений (с плавающей запятой). |
|
Формирует F-распределение (также известное как F-распределение Снедекора или распределение Фишера-Снедекора) вещественных значений (с плавающей запятой). |
|
Формирует логарифмически нормальное распределение вещественных значений (с плавающей запятой). |
|
Формирует нормальное (Гауссово) распределение вещественных значений (с плавающей запятой). |
|
Формирует t-распределение Стьюдента вещественных значений (с плавающей запятой). |
[в начало раздела]
Распределения Пуассона
Формирует экспоненциальное распределение вещественных значений (с плавающей запятой). |
|
Формирует распределение экстремальных вещественных значений (с плавающей запятой). |
|
Формирует гамма-распределение вещественных значений (с плавающей запятой). |
|
Формирует распределение Пуассона целых значений. |
|
Формирует распределение Вейбулла вещественных значений (с плавающей запятой). |
[в начало раздела]
Выборочные распределения
Формирует дискретное распределение целых чисел. |
|
Формирует кусочно-постоянное распределение вещественных значений (с плавающей запятой). |
|
Формирует кусочно-линейное распределение вещественных значений (с плавающей запятой). |
[в начало раздела]
[в начало страницы]
Служебные функции
В этом разделе перечислены основные служебные функции, доступные в заголовке <random>.
Создает шифрованную порождающую последовательность без смещения. Используется для предотвращения повтора потоков случайных чисел. Полезно, если на основе механизмов инициализируется множество РГСЧ. |
Операторы
В этом разделе перечислены операторы, доступные в заголовке <random>.
operator== |
Проверка на то, что РГСЧ с левой стороны оператора равен механизму с правой стороны. |
operator!= |
Проверка на то, что РГСЧ с левой стороны оператора не равен механизму с правой стороны. |
operator<< |
Запись сведений о состоянии в поток. |
operator>> |
Извлечение сведений о состоянии из потока. |
[в начало страницы]
Механизмы и распределения
Сведения о каждой категории класса шаблонов, заданных в <random>, см. в следующих разделах. Обе категории принимают тип в качестве аргумента и используют общие имена параметров шаблона для описания свойств типа, которые можно использовать как тип фактического аргумента, как показано далее.
IntType обозначает short, int, long, long long, unsigned short, unsigned int, unsigned long или unsigned long long.
UIntType обозначает unsigned short, unsigned int, unsigned long или unsigned long long.
RealType обозначает float, double или long double.
Механизмы
Механизмы и адаптеры механизмов — это шаблоны, параметры которых настраивают созданный генератор.
Механизм — это класс или класс шаблона, экземпляры которых (генераторы) служат источником случайных чисел, равномерно распределенных между минимальным и максимальным значениями. Адаптер механизма предоставляет последовательность значений с различной стохастичностью, беря значения, сформированные другим механизмом случайных чисел, и применяя к ним определенный алгоритм.
Каждый механизм и адаптер механизма содержат следующие члены.
typedef numeric-type result_type — это тип, возвращаемый функцией operator() генератора. numeric-type передается как параметр шаблона при создании экземпляра.
result_type operator() возвращает значения, которые равномерно распределены между min() и max().
result_type min() возвращает минимальное значение, полученное от функции operator() генератора. Адаптеры механизма используют результат функции min() базового механизма.
result_type max() возвращает максимальное значение, полученное от функции operator() генератора. Если result_type — это целочисленный тип, то max() — это максимальное значение, которое может быть возвращено (инклюзивное). Если result_type — это вещественное значение, то max() — это наименьшее значение, превышающее все значения, которые могут быть возвращены (неинклюзивное). Адаптеры механизма используют результат функции max() базового механизма.
void seed(result_type s) задает для генератора начальное значение s. Для механизмов используется сигнатура void seed(result_type s = default_seed) для поддержки параметров по умолчанию (в адаптерах механизмов определена отдельная функция void seed(), как показано далее).
template <class Seq> void seed(Seq& q) задает для генератора начальное значение, используя seed_seq Seq.
Явный конструктор с аргументом result_type x, который создает генератор, начальное значение которого определяется так же, как при вызове функции seed(x).
Явный конструктор с аргументом seed_seq& seq, который создает генератор, начальное значение которого определяется так же, как при вызове функции seed(seq).
void discard(unsigned long long count) вызывает функцию operator() count раз и удаляет каждое значение.
Адаптеры механизмов также поддерживают следующие члены (Engine — это первый параметр шаблона адаптера механизма, обозначающий тип базового механизма).
Конструктор по умолчанию, который инициализирует генератор так же, как конструктор базового механизма по умолчанию.
Явный конструктор с аргументом const Engine& eng. Это необходимо для поддержки конструкции копирования с использованием базового механизма.
Явный конструктор с аргументом Engine&& eng. Это необходимо для поддержки конструкции перемещения с использованием базового механизма.
void seed() инициализирует генератор с использованием начального значения базового механизма по умолчанию.
Функция свойства const Engine& base() возвращает базовый механизм, который использовался для создания генератора.
Каждый механизм поддерживает состояние, определяющее последовательность значений, которые будут созданы последующими вызовами operator(). Состояние двух генераторов, созданных на основе механизмов одного типа, можно сравнить с помощью операторов operator== и operator!=. Если два состояния равны, генераторы будут получать одинаковые последовательности значений. Состояние объекта можно сохранить в поток как последовательность 32-разрядных беззнаковых значений, используя оператор operator<< генератора. Состояние после сохранения не изменяется. Сохраненное состояние можно считать в генератор, созданный на основе механизма того же типа, используя оператор operator>>.
[в начало страницы]
Распределения
distribution — это класс или класс шаблона, экземпляры которого преобразуют поток равномерно распределенных случайных чисел, полученных от механизма, в поток случайных чисел с частичным распределением. У каждого распределения есть следующие члены.
typedef numeric-type result_type — это тип, возвращаемый функцией operator() распределения. numeric-type передается как параметр шаблона при создании экземпляра.
template <class URNG> result_type operator()(URNG& gen) возвращает значения, которые распределяются в соответствии с определением распределения, используя gen в качестве источника случайных значений с равномерным распределением и сохраненные параметры распределения.
template <class URNG> result_type operator()(URNG& gen, param_type p) возвращает значения, которые распределены в соответствии с определением распределения, используя gen в качестве источника случайных значений с равномерным распределением и структуру параметров p.
typedef unspecified-type param_type — это пакет параметров, которые могут передаваться функции operator() и использоваться вместо сохраненных параметров для формирования возвращаемого значения.
Конструктор const param& инициализирует сохраненные параметры на основе своего аргумента.
param_type param() const получает сохраненные параметры.
void param(const param_type&) задает сохраненные параметры на основе своего аргумента.
result_type min() возвращает минимальное значение, полученное от функции operator() распределения.
result_type max() возвращает максимальное значение, полученное от функции operator() распределения. Если result_type — это целочисленный тип, то max() — это максимальное значение, которое может быть возвращено (инклюзивное). Если result_type — это вещественное значение, то max() — это наименьшее значение, превышающее все значения, которые могут быть возвращены (неинклюзивное).
void reset() удаляет любые кэшированные значения, чтобы результат следующего вызова operator() не зависел от любых значений, полученных от механизма перед вызовом.
Структура параметров — это объект, в котором хранятся все параметры, необходимые для распределения. Она содержит следующее.
typedef distribution-type distribution_type, тип распределения.
Один или несколько конструкторов, которые принимают такие же наборы параметров, что и конструкторы распределения.
Такие же функции параметров и доступа, как у распределения.
Операторы сравнения равенства и неравенства.
Дополнительные сведения см. ниже в справочных подразделах, указанных ранее в этой статье.
[в начало страницы]
Примечания
В Visual Studio есть два очень полезных РГСЧ — mt19937 и random_device, которые показаны в следующей таблице.
РГСЧ |
Быстрый? |
Криптобезопасный? |
С начальным значением? |
Детерминистический? |
---|---|---|---|---|
mt19937 |
Да |
Нет |
Да |
Да * |
random_device |
Нет |
Да |
Нет |
Нет |
* Если предоставлено известное начальное значение.
Хотя согласно стандарту ISO для C++ функция random_device не обязана быть криптографически безопасной, в Visual Studio она реализована как криптобезопасная. (Термин "криптографически безопасный" не подразумевает каких-то гарантий, но обозначает минимальный уровень энтропии, а значит, и уровень предсказуемости данного алгоритма рандомизации. Дополнительные сведения см. в статье Википедии Криптографически стойкий генератор псевдослучайных чисел.) Так как в стандарте ISO для C++ нет такого требования, на других платформах функция random_device может быть реализована как простой генератор псевдослучайных чисел (не криптобезопасный) и может использоваться как источник начальных значений для другого генератора. При использовании random_device в коде для разных платформ изучите документацию по этим платформам.
По определению, результаты random_device не воспроизводятся повторно; это значит, что эта функция может работать значительно медленнее, чем другие РГСЧ. Большинство приложений, которые не должны быть криптобезопасными, используют mt19937 или аналогичный механизм, хотя для заполнения начального значения можно вызвать random_device, как показано в этом примере кода.
[в начало страницы]