Генерация случайного числа в заданном диапазоне

Функции srand() и rand()

Языки Cи и C++ имеют свои собственные встроенные генераторы случайных чисел. Они реализованы в 2-х отдельных функциях, которые находятся в заголовочном файле cstdlib:

   Функция srand() устанавливает передаваемое пользователем значение в качестве стартового. srand() следует вызывать только один раз — в начале программы (обычно в верхней части функции main()).

   Функция rand() генерирует следующее случайное число в последовательности. Оно будет находиться в диапазоне от до RAND_MAX (константа в cstdlib, значением которой является 32767).

Вот пример программы, в которой используются обе эти функции:

Результат выполнения программы:

14867   24680   8872    25432   21865 17285   18997   10570   16397   30572 22339   31508   1553    124     779 6687    23563   5754    25989   16527 19808   10702   13777   28696   8131 18671   27093   8979    4088    31260 31016   5073    19422   23885   18222 3631    19884   10857   30853   32618 31867   24505   14240   14389   13829 13469   11442   5385    9644    9341 11470   189     3262    9731    25676 1366    24567   25223   110     24352 24135   459     7236    17918   1238 24041   29900   24830   1094    13193 10334   6192    6968    8791    1351 14521   31249   4533    11189   7971 5118    19884   1747    23543   309 28713   24884   1678    22142   27238 6261    12836   5618    17062   13342 14638   7427    23077   25546   21229

Использование random_device в качестве seed для ГПСЧ

std::random_devicerd{};  std::default_random_enginee{ rd() };  

Ничего принципиально нового в этом коде нет. При этом с каждым запуском ГПСЧ инициализируется случайными значениями, которые создает генератор истинно случайных чисел rd.

Стоит также отметить, что значение инициализации генератора может быть сброшено в любой момент:

e.seed(15027);// инициализация числом  e.seed(); //инициализация значением по умолчанию  e.seed( rd() );//инициализация другим генератором  

Функция rand().

Данная функция возвращает случайное целое число в диапазоне от нуля до RAND_MAX. RAND_MAX это специальная константа языка Си, в которой содержится максимальное целое число, которое может быть возвращено функцией rand().

Функция rand() определена в заголовочном файле stdlib.h. Поэтому, если хотите использовать rand в своей программе, не забудьте подключить этот заголовочный файл. Константа RAND_MAX тоже определена в этом файле. Вы можете найти этот файл у себя на компьютере и посмотреть её значение.

Давайте посмотрим на эту функцию в действии. Запустим следующий код:

Листинг 1.

Должно получиться что-то вроде этого.

rand.png

Рис.1 Пять случайных чисел, сгенерированных функцийе rand

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

Ограничить случайные числа сверху.

Кто в школе ждал момента, когда ему пригодится математика, приготовьтесь. Этот момент наступил. Чтобы ограничить сверху случайные числа, можно воспользоваться операцией получения остатка от деления, которую вы изучили в прошлом уроке. Наверное вы знаете, что остаток от деления на числа K всегда меньше числа K. Например, при делении на 4 могут получиться остатки 0, 1, 2 и 3. Поэтому если вы хотите ограничить сверху случайные числа числом K, то просто возьмите остаток от деления на K. Вот так:

Листинг 2.

rand_do_100.png

Рис.2 Пять случайных чисел меньше 100

Ограничить числа снизу.

Функция rand возвращает случайные числа из отрезка [0, RAND_MAX]. А что если нам нужны только числа большие числа M (например, 1000)? Как быть? Всё просто. Просто прибавим к тому, что вернула функция rand, наше значение M. Тогда если функция вернёт , итоговый ответ будет M, если 2394, то итоговый ответ будет M + 2394. Этим действием мы как бы сдвигаем все числа на M единиц вперёд.

Задать границы функции rand сверху и снизу.

Например, получить числа от 80 до 100. Кажется, нужно просто объединить два способа, которые приведены выше. Получим что-то вроде этого:

Листинг 3.

Попробуйте запустить эту программу. Удивлены?

Да, такой способ работать не будет. Давайте прокрутим эту программу руками, чтобы убедиться в том, что мы допустили ошибку. Допустим rand() вернула число 143. Остаток от деления на 100 равен 43. Дальше 80 + 43 = 123. Значит такой способ не работает. Подобная конструкция выдаст числа от 80 до 179.

Давайте разберём по действиям наше выражение. rand()%100 может выдать числа от до 99 включительно. Т.е. из отрезка [0; 99]. Операция + 80 сдвигает наш отрезок на 80 единиц вправо. Получаем [80; 179]. Как видим, проблема у нас заключается в правой границе отрезка, она сдвинута вправо на 79 единиц. Это наше исходное число 80 минус 1. Давайте наведём порядок и сдвинем правую границу назад: 80 + rand()%(100 — 80 + 1). Тогда всё должно сработать как надо.

В общем случае если нам нужно получить числа из отрезка [A;B], то необходимо воспользоваться следующей конструкцией:A + rand()%(B-A+1).

Согласно этой формуле перепишем нашу последнюю программу:

Листинг 4.

Результат работы:

Рис.3 Случайные числа из диапазона [80;100]

Ну вот, теперь вы можете решить исходную задачу урока. Сгенерировать число из отрезка [1; N]. Или не можете?

Но прежде ещё немного полезной информации. Запустите последнюю программу три раза подряд и записывайте себе случайные числа, которые она генерирует. Заметили?

Почему генератор создает одинаковые последовательности?

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

Соответственно, чтобы избежать повторения последовательности чисел, генератор должен инициализироваться разными значениями при каждом запуске программы. Как раз для этих целей можно использовать seed. Стандартным способом инициализации ГПСЧ является передача ему в качестве seed значения time(0) из заголовочного файла ctime. То есть генератор будет инициализироваться значением, равным количеству секунд, прошедших с момента 1 января 00 часов 00 минут 00 секунд, 1970 года по UTC.

Оцените статью
Рейтинг автора
5
Материал подготовил
Илья Коршунов
Наш эксперт
Написано статей
134
Добавить комментарий