Чтение онлайн

ЖАНРЫ

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

Пример 11.10 иллюстрирует работу функции

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

Пример 11.10. Пример реализации функции accumulate

template<class Iter_T, class Value_T, class BinOp_T>

Iter_T accumulate(Iter_T begin, Iter_T end, Value_T value, BinOp_T op) {

 while (begin != end) {

value = op(value, *begin++)

 }

 return value;

}

11.6.

Генерация случайных чисел

Проблема

Требуется сгенерировать несколько случайных чисел в формате с плавающей точкой в интервале значений

[0.0, 1.0)
при равномерном их распределении.

Решение

Стандарт C++ предусматривает наличие C-функции библиотеки этапа исполнения

rand
, определенной в заголовочном файле
<cstdlib>
, которая возвращает случайное число в диапазоне от 0 до
RAND_MAX
включительно. Макропеременная
RAND_MAX
представляет собой максимальное значение, которое может быть возвращено функцией
rand
. Пример 11.11 демонстрирует применение функции
rand
для генерации случайных чисел с плавающей точкой.

Пример 11.11. Генерация случайных чисел функцией rand

#include <cstdlib>

#include <ctime>

#include <iostream>

using namespace std;

double doubleRand {

 return double(rand) / (double(RAND_MAX) + 1.0);

}

int main {

 srand(static_cast<unsigned int>(clock));

 cout << "expect 5 numbers within the interval [0.0, 1.0)" << endl;

 for (int i=0; i < 5; i++) {

cout << doubleRand << "\n";

 }

 cout << endl;

}

Программа примера 11.11 должна выдать результат, подобный следующему.

expect 5 numbers within the interval [0.0, 1.0)

0.010437

0.740997

0.34906

0.369293

0.544373

Обсуждение

Необходимо уточнить, что функции, генерирующие случайные числа (в том числе

rand
), возвращают псевдослучайные числа, а не реальные случайные числа, поэтому там, где я говорю «случайное число», я на самом деле имею в виду псевдослучайное число.

Перед применением функции

rand
вы должны «посеять» (т.е. инициализировать) генератор случайных чисел с помощью вызова функции
srand
. Это обеспечивает генерацию последующими вызовами
rand
разных последовательностей чисел при каждом новом исполнении программы. Проще всего инициализировать генератор случайных чисел путем передачи ему результата вызова функции
clock
из заголовочного файла
<ctime>
, имеющего тип
unsigned int
. Повторная инициализация генератора случайных чисел приводит к тому, что генерируемые числа становятся менее случайными.

Функция

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

Значительно более изощренную альтернативу

rand
представляет написанная Джензом Маурером (Jens Maurer) библиотека Boost Random; она была инспирирована предложениями по генерации случайных чисел, представленными в TR1.

TR1 означает «Technical Report One» и представляет собой официальный проект по расширению стандартной библиотеки C++98.

Библиотека Boost Random содержит несколько высококачественных функций по генерации случайных чисел как для целых типов, так и для типов с плавающей точкой, причем с поддержкой многочисленных распределений. Пример 11.12 показывает, как можно сгенерировать случайные числа с плавающей точкой в интервале значений

[0,1)
.

Пример 11.12. Использование библиотеки Boost Random

#include <boost/random.hpp>

#include <iostream>

#include <cstdlib>

using namespace std;

using namespace boost;

typedef boost::mt19937 BaseGenerator;

typedef boost::uniform_real<double> Distribution;

typedef boost::variate_generator<BaseGenerator, Distribution> Generator;

double boostDoubleRand {

 static BaseGenerator base;

 static Distribution dist;

 static Generator rng(base, dist);

 return rng;

}

int main {

 cout << "expect 5 numbers within the interval [0.1)" << endl;

 for (int i=0; i < 5; i++) {

cout << boostDoubleRand << "\n";

 }

 cout << endl;

}

Основное преимущество библиотеки Boost Random в том, что алгоритм генерации псевдослучайных чисел обеспечивает гарантированные и воспроизводимые свойства случайных последовательностей, зависящих от выбранного алгоритма. В примере 11.12 я использую генератор Mersenne Twister (

mt19937
), потому что он дает хорошее сочетание производительности и качества последовательности случайных чисел.

11.7. Инициализация контейнера случайными числами

Проблема

Требуется заполнить произвольный контейнер случайными числами.

Решение

Можно использовать функции

generate
и
generate_n
из заголовочного файла
<algorithm>
совместно с функтором, возвращающим случайные числа. Пример 11.13 показывает, как это можно сделать.

Пример 11.13. Инициализация контейнеров случайными числами

Поделиться с друзьями: