Требуется сгенерировать несколько случайных чисел в формате с плавающей точкой в интервале значений
[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
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
), потому что он дает хорошее сочетание производительности и качества последовательности случайных чисел.