Spec-Zone.ru › C++

Генерация псевдослучайных чисел

Библиотека генерации случайных чисел предоставляет классы для генерации случайных и псевдослучайных чисел. К ним относятся:

  • Равномерные генераторы случайных битов (URBG), включая движки случайных чисел — генераторы псевдослучайных чисел, создающие целочисленные последовательности с равномерным распределением, — и генераторы истинно случайных чисел (если доступны).
  • Распределения случайных чисел (например, равномерное, нормальное или распределение Пуассона), преобразующие выходные данные URBG в различные статистические распределения.

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

Равномерные генераторы случайных битов

Равномерный генератор случайных битов — это функциональный объект, возвращающий беззнаковые целочисленные значения, причём каждое значение из диапазона возможных результатов (в идеале) имеет одинаковую вероятность возврата.

Все равномерные генераторы случайных битов соответствуют требованиям UniformRandomBitGenerator. В C++20 также определено понятие uniform_random_bit_generator.

Определён в заголовочном файле <random>
uniform_random_bit_generator
(C++20)
указывает, что тип соответствует требованиям равномерного генератора случайных битов
(понятие)

Движки случайных чисел

Движок случайных чисел (обычно сокращённо движок ) — это равномерный генератор случайных битов, создающий псевдослучайные числа с использованием начальных данных в качестве источника энтропии.

В любой момент времени движок e типа E имеет состояние ei для некоторого неотрицательного целого числа i. При создании e имеет начальное состояние e0, определяемое параметрами движка и начальным значением (или последовательностью начальных значений).

Для любого типа движка E всегда определены следующие свойства:

  • Размер состояния E в единицах размера E::result_type (то есть (sizeof ei) / sizeof(E::result_type)).
  • Алгоритм перехода TA, с помощью которого состояние e ei переходит в следующее состояние ei+1 (то есть TA(ei) == ei+1).
  • Алгоритм генерации GA, с помощью которого состояние e отображается в значение типа E::result_type; результатом является псевдослучайное число.

Последовательность псевдослучайных чисел можно сгенерировать, попеременно вызывая TA и GA.

Стандартная библиотека предоставляет реализации трёх различных классов алгоритмов генерации псевдослучайных чисел в виде шаблонов классов, что позволяет настраивать алгоритмы. Выбор движка связан с рядом компромиссов:

  • Линейный конгруэнтный движок работает с умеренной скоростью и требует очень мало памяти для хранения состояния.
  • Движок вихря Мерсенна работает медленнее и требует больше памяти для хранения состояния, но при правильном выборе параметров обеспечивает самую длинную неповторяющуюся последовательность с наиболее желательными спектральными характеристиками (при заданном определении желательных характеристик).
  • Движок вычитания с заёмом работает очень быстро даже на процессорах без расширенных наборов арифметических инструкций, но требует больше памяти для хранения состояния и иногда обладает менее желательными спектральными характеристиками.
  • Движок Philox — это генератор случайных чисел на основе счётчика. Он имеет небольшое состояние и длинный период (не менее 2^130) и предназначен для использования в симуляциях методом Монте-Карло, требующих массовой параллельной генерации случайных чисел. Он легко поддаётся векторизации и распараллеливанию и реализован в библиотеках, оптимизированных для GPU.
(начиная с C++26)

Ни один из этих движков случайных чисел не является криптографически стойким. Как и для любой защищённой операции, для этих целей следует использовать криптографическую библиотеку (например, OpenSSL RAND_bytes).

Все типы, созданные на основе этих шаблонов, соответствуют требованиям RandomNumberEngine.

Определён в заголовочном файле <random>
linear_congruential_engine
(C++11)
реализует алгоритм линейного конгруэнтного генератора
(шаблон класса)
mersenne_twister_engine
(C++11)
реализует алгоритм вихря Мерсенна
(шаблон класса)
subtract_with_carry_engine
(C++11)
реализует алгоритм вычитания с заёмом (генератор Фибоначчи с запаздыванием)
(шаблон класса)
philox_engine
(C++26)
параллелизуемый генератор на основе счётчика
(шаблон класса)

Адаптеры движков случайных чисел

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

Определён в заголовочном файле <random>
discard_block_engine
(C++11)
отбрасывает часть выходных данных движка случайных чисел
(шаблон класса)
independent_bits_engine
(C++11)
упаковывает выходные данные движка случайных чисел в блоки заданного числа битов
(шаблон класса)
shuffle_order_engine
(C++11)
выдаёт выходные данные движка случайных чисел в ином порядке
(шаблон класса)

Предопределённые генераторы случайных чисел

Предопределено несколько популярных алгоритмов.

Определён в заголовочном файле <random>
Тип Определение
minstd_rand0 (C++11) std::linear_congruential_engine<std::uint_fast32_t,
16807,0,2147483647>
Открыт в 1969 году Льюисом, Гудманом и Миллером; принят как «минимальный стандарт» в 1988 году Парком и Миллером
minstd_rand (C++11)

std::linear_congruential_engine<std::uint_fast32_t,
48271,0,2147483647>
Более новый «минимальный стандарт», рекомендованный Парком, Миллером и Стокмайером в 1993 году

mt19937 (C++11)

std::mersenne_twister_engine<std::uint_fast32_t,
32,624,397,31,
0x9908b0df,11,
0xffffffff,7,
0x9d2c5680,15,
0xefc60000,18,1812433253>
32-разрядный вихрь Мерсенна, созданный Мацумото и Нисимурой в 1998 году

mt19937_64 (C++11)

std::mersenne_twister_engine<std::uint_fast64_t,
64,312,156,31,
0xb5026f5aa96619e9,29,
0x5555555555555555,17,
0x71d67fffeda60000,37,
0xfff7eee000000000,43,
6364136223846793005>
64-разрядный вихрь Мерсенна, созданный Мацумото и Нисимурой в 2000 году

ranlux24_base (C++11) std::subtract_with_carry_engine<std::uint_fast32_t,24,10,24>
ranlux48_base (C++11) std::subtract_with_carry_engine<std::uint_fast64_t,48,5,12>
ranlux24 (C++11) std::discard_block_engine<std::ranlux24_base,223,23>

24-разрядный генератор RANLUX, созданный Мартином Люшером и Фредом Джеймсом в 1994 году

ranlux48 (C++11) std::discard_block_engine<std::ranlux48_base,389,11>

48-разрядный генератор RANLUX, созданный Мартином Люшером и Фредом Джеймсом в 1994 году

knuth_b (C++11) std::shuffle_order_engine<std::minstd_rand0,256>
philox4x32 (C++26) std::philox_engine<std::uint_fast32_t,32,4,10,
0xCD9E8D57,0x9E3779B9,
0xD2511F53,0xBB67AE85>
philox4x64 (C++26) std::philox_engine<std::uint_fast64_t,64,4,10,
0xCA5A826395121157,0x9E3779B97F4A7C15,
0xD2E7470EE14C6C93,0xBB67AE8584CAA73B>
default_random_engine (C++11) тип RandomNumberEngine, определяемый реализацией

Недетерминированные случайные числа

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

random_device
(C++11)
недетерминированный генератор случайных чисел, использующий аппаратный источник энтропии
(класс)

Распределения случайных чисел

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

Распределения случайных чисел соответствуют требованиям RandomNumberDistribution.

Определён в заголовочном файле <random>
Равномерные распределения
uniform_int_distribution
(C++11)
генерирует целочисленные значения, равномерно распределённые в диапазоне
(шаблон класса)
uniform_real_distribution
(C++11)
генерирует вещественные значения, равномерно распределённые в диапазоне
(шаблон класса)
Распределения Бернулли
bernoulli_distribution
(C++11)
генерирует значения bool в соответствии с распределением Бернулли
(класс)
binomial_distribution
(C++11)
генерирует целочисленные значения в соответствии с биномиальным распределением
(шаблон класса)
negative_binomial_distribution
(C++11)
генерирует целочисленные значения в соответствии с отрицательным биномиальным распределением
(шаблон класса)
geometric_distribution
(C++11)
генерирует целочисленные значения в соответствии с геометрическим распределением
(шаблон класса)
Распределения Пуассона
poisson_distribution
(C++11)
генерирует целочисленные значения в соответствии с распределением Пуассона
(шаблон класса)
exponential_distribution
(C++11)
генерирует вещественные значения в соответствии с экспоненциальным распределением
(шаблон класса)
gamma_distribution
(C++11)
генерирует вещественные значения в соответствии с гамма-распределением
(шаблон класса)
weibull_distribution
(C++11)
генерирует вещественные значения в соответствии с распределением Вейбулла
(шаблон класса)
extreme_value_distribution
(C++11)
генерирует вещественные значения в соответствии с распределением экстремальных значений
(шаблон класса)
Нормальные распределения
normal_distribution
(C++11)
генерирует вещественные значения в соответствии со стандартным нормальным (гауссовым) распределением
(шаблон класса)
lognormal_distribution
(C++11)
генерирует вещественные значения в соответствии с логнормальным распределением
(шаблон класса)
chi_squared_distribution
(C++11)
генерирует вещественные значения в соответствии с распределением хи-квадрат
(шаблон класса)
cauchy_distribution
(C++11)
генерирует вещественные значения в соответствии с распределением Коши
(шаблон класса)
fisher_f_distribution
(C++11)
генерирует вещественные значения в соответствии с F-распределением Фишера
(шаблон класса)
student_t_distribution
(C++11)
генерирует вещественные значения в соответствии с t-распределением Стьюдента
(шаблон класса)
Распределения выборки
discrete_distribution
(C++11)
генерирует целочисленные значения в соответствии с дискретным распределением
(шаблон класса)
piecewise_constant_distribution
(C++11)
генерирует вещественные значения, распределённые по заданным постоянным подынтервалам
(шаблон класса)
piecewise_linear_distribution
(C++11)
генерирует вещественные значения, распределённые по заданным подынтервалам линейно
(шаблон класса)

Утилиты

Определён в заголовочном файле <random>
generate_canonical
(C++11)
равномерно распределяет вещественные значения заданной точности по диапазону [0, 1)
(шаблон функции)
seed_seq
(C++11)
универсальный генератор перемешанной последовательности начальных значений, устраняющий смещение
(класс)

Алгоритмы генерации случайных чисел

Определён в заголовке <random>
ranges::generate_random
(C++26)
заполняет диапазон случайными числами из равномерного генератора случайных битов
(функциональный объект алгоритма)

Библиотека случайных чисел C

Помимо описанных выше генераторов и распределений, доступны также функции и константы из библиотеки случайных чисел C, хотя их использование не рекомендуется:

Определён в заголовке <cstdlib>
rand
генерирует псевдослучайное число
(функция)
srand
инициализирует генератор псевдослучайных чисел
(функция)
RAND_MAX
максимальное возможное значение, генерируемое std::rand
(макроконстанта)

Пример

#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <random>
#include <string>

int main()
{
    // Seed with a real random value, if available
    std::random_device r;
    
    // Choose a random mean between 1 and 6
    std::default_random_engine e1(r());
    std::uniform_int_distribution<int> uniform_dist(1, 6);
    int mean = uniform_dist(e1);
    std::cout << "Randomly-chosen mean: " << mean << '\n';
    
    // Generate a normal distribution around that mean
    std::seed_seq seed2{r(), r(), r(), r(), r(), r(), r(), r()};
    std::mt19937 e2(seed2);
    std::normal_distribution<> normal_dist(mean, 2);
    
    std::map<int, int> hist;
    for (int n = 0; n != 10000; ++n)
        ++hist[std::round(normal_dist(e2))];
    
    std::cout << "Normal distribution around " << mean << ":\n"
              << std::fixed << std::setprecision(1);
    for (auto [x, y] : hist)
        std::cout << std::setw(2) << x << ' ' << std::string(y / 200, '*') << '\n';
}

Возможный вывод:

Randomly-chosen mean: 4
Normal distribution around 4:
-4
-3
-2
-1
 0 *
 1 ***
 2 ******
 3 ********
 4 *********
 5 ********
 6 ******
 7 ***
 8 *
 9
10
11
12

См. также

Документация C по теме Генерация псевдослучайных чисел

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/numeric/random

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API