Что, если мы хотим смоделировать бросок кубика? Конечно, можно написать код (rand()%6)+1
А если мы хотим смоделировать событие, которое случается с вероятностью 66%? Окей, можно создать формулу наподобие bool yesno = (rand()%100>66)
>=
или правильнее будет оставить оператор >?
)Кроме того, как смоделировать бросок
Библиотека содержит более дюжины алгоритмов распределения, которые могут формировать случайные числа для определенных потребностей. В этом примере мы очень кратко рассмотрим их все, а также более детально взглянем на самые полезные.
Как это делается
В этом примере мы будем генерировать случайные числа, придавать им форму и выводить на экран шаблоны распределения. Таким образом, рассмотрим их все и разберем их самые важные свойства, которые могут оказаться полезными, если потребуется смоделировать что-то конкретное.
1. Сначала включим все необходимые заголовочные файлы и объявим об использовании пространства имен std
#include
#include
#include
#include
#include
#include
using namespace std;
2. Для каждого распределения, предоставляемого STL, выведем гистограмму, чтобы увидеть его характеристики, поскольку каждое из них выглядит особенным образом. Гистограмма принимает в качестве аргумента распределение и количество образцов, которые будут взяты из него. Затем создадим генератор случайных чисел по умолчанию и ассоциативный массив. В последнем будут соотнесены значения, полученные из распределения, со счетчиками, показывающими, как часто встречается то или иное значение. Мы всегда создаем экземпляр генератора случайных чисел, потому что все распределения используются только в качестве
template
void print_distro(T distro, size_t samples)
{
default_random_engine e;
map
3. Возьмем столько образцов, сколько указано в переменной samples
e()
даст необработанное простое число, distro(e)
придает случайным числам форму с помощью объекта распределения: for (size_t i {0}; i < samples; ++i) {
m[distro(e)] += 1;
}
4. Чтобы получить выходные данные, которые помещаются в окно консоли, нужно узнать
max_element
поможет определить такое значение путем сравнения всех связанных счетчиков в массиве и возвращения итератора, указывающего на узел, содержащий данное значение. Зная это значение, можем определить, на какое число следует разделить все значения счетчиков, чтобы уместить полученный результат в окно консоли. size_t max_elm (max_element(begin(m), end(m),
[](const auto &a, const auto &b) {
return a.second < b.second;
})->second);
size_t max_div (max(max_elm / 100, size_t(1)));
5. Теперь пройдем по массиву в цикле и выведем полоски из символов '*'
for (const auto [randval, count] : m) {
if (count < max_elm / 200) { continue; }
cout << setw(3) << randval << " : "
<< string(count / max_div, '*') << '\n';
}
}
6. В функции main
int main(int argc, char **argv)
{
if (argc != 2) {
cout << "Usage: " << argv[0]
<< "
}
7. Теперь преобразуем аргумент командной строки в число с помощью вызова std::stoull
size_t samples {stoull(argv[1])};