Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
using Numeric_lib::Index;
24.7. Случайные числа
Если вы попросите любого человека назвать случайное число, то они назовут 7 или 17, потому что эти числа считаются самыми случайными. Люди практически никогда не называют число нуль, так как оно кажется таким идеально круглым числом, что не воспринимается как случайное, и поэтому его считают наименее случайным числом. С математической точки зрения это полная бессмыслица: ни одно отдельно взятое число нельзя назвать случайным. То, что мы часто
Как практический инструмент и математическая проблема случайные числа в настоящее время достигли настолько высокой степени сложности, что стали широко использоваться в реальных приложениях. Здесь мы лишь коснемся основ теории случайных чисел, необходимых для осуществления простого тестирования и моделирования. В заголовке
<cstdlib>
из стандартной библиотеки есть такой код:
int rand; // возвращает числа из диапазона
// [0:RAND_MAX]
RAND_MAX // наибольшее число, которое генерирует
// датчик rand
void srand(unsigned int); // начальное значение датчика
// случайных чисел
Повторяющиеся вызовы функции
rand
генерируют последовательность чисел типа int
, равномерно распределенных в диапазоне [0:RAND_MAX]
. Эта последовательность чисел называется псевдослучайной, потому что она генерируется с помощью математической формулы и с определенного места начинает повторяться (т.е. становится предсказуемой и не случайной). В частности, если мы много раз вызовем функцию rand
в программе, то при каждом запуске программы получим одинаковые последовательности. Это чрезвычайно полезно для отладки. Если же мы хотим получать разные последовательности, то должны вызывать функцию srand
с разными значениями. При каждом новом аргументе функции srand
функция rand
будет порождать разные последовательности. Например, рассмотрим функцию
random_vector
, упомянутую в разделе 24.6.3. Вызов функции random_vector(n)
порождает объект класса Matrix<double,1>
, содержащий n
элементов, представляющих собой случайные числа в диапазоне от [0:n]
:
Vector random_vector(Index n)
{
Vector v(n);
for (Index i = 0; i < n; ++i)
v(i) = 1.0 * n * rand / RAND_MAX;
return v;
}
Обратите внимание на использование числа
1.0
, гарантирующего, что все вычисления будут выполнены в арифметике с плавающей точкой. Иначе при каждом делении целого числа на RAND_MAX
мы получали бы 0
. Сложнее получить целое число из заданного диапазона, например
[0:max]
. Большинство людей сразу предлагают следующее решение:
int val = rand%max;
Долгое
int randint(int max) { return rand%max; }
int randint(int min, int max) { return randint(max–min)+min; }
Таким образом, мы можем скрыть определение функции
randint
, если окажется, что реализация функции rand
является неудовлетворительной. В промышленных программных системах, а также в приложениях, где требуются неравномерные распределения, обычно используются качественные и широко доступные библиотеки случайных чисел, например Boost::random
. Для того чтобы получить представление о качестве вашего датчика случайных чисел, выполните упр. 10. 24.8. Стандартные математические функции
В стандартной библиотеке есть стандартные математические функции (
cos
, sin
, log
и т.д.). Их объявления можно найти в заголовке <cmath>
. Стандартные математические функции могут иметь аргументы типов
float
, double
, long double
и complex
(раздел 24.9). Эти функции очень полезны при вычислениях с плавающей точкой. Более подробная информация содержится в широко доступной документации, а для начала можно обратиться к документации, размещенной в веб.
Если стандартная математическая функция не может дать корректного результата, она устанавливает флажок
errno
. Рассмотрим пример.
errno = 0;
double s2 = sqrt(–1);
if (errno) cerr << "Что-то где-то пошло не так, как надо";
if (errno == EDOM) // ошибка из-за выхода аргумента
// за пределы области определения
cerr << " фунция sqrt для отрицательных аргументов
не определена.";
pow(very_large,2); // плохая идея
if (errno==ERANGE) // ошибка из-за выхода за пределы допустимого
// диапазона
cerr << "pow(" << very_large
<< ",2) слишком большое число для double";
Если вы выполняете серьезные математические вычисления, то всегда должны проверять значение
errno
, чтобы убедиться, что после возвращения результата оно по-прежнему равно 0
. Если нет, то что-то пошло не так, как надо. Для того чтобы узнать, какие математические функции могут устанавливать флажок errno
и чему он может быть равен, обратитесь к документации.
Поделиться:
Популярные книги
Вираж бытия
1. Фрунзе
Фантастика:
героическая фантастика
попаданцы
альтернативная история
6.86
рейтинг книги
Кодекс Крови. Книга IХ
9. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эфемер
7. Стеллар
Фантастика:
боевая фантастика
рпг
7.23
рейтинг книги
Попаданка в академии драконов 4
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Крестоносец
7. Помещик
Фантастика:
героическая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Промышленникъ
3. Александр Агренев
Приключения:
исторические приключения
9.13
рейтинг книги
Ротмистр Гордеев 2
2. Ротмистр Гордеев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Безумный Макс. Поручик Империи
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Фиктивный брак
Фантастика:
фэнтези
6.71
рейтинг книги
Набирая силу
2. Альфа-ноль
Фантастика:
фэнтези
боевая фантастика
рпг
6.29
рейтинг книги
Имперец. Земли Итреи
11. Путь
Фантастика:
героическая фантастика
боевая фантастика
5.25
рейтинг книги
Титан империи
1. Титан Империи
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Странник
4. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Мне нужна жена
Любовные романы:
современные любовные романы
6.88