Генерация случайных чисел в языке Си
Иногда может возникнуть необходимость в генерации случайных чисел. Простой пример.
Пример: Определение победителя в конкурсе репостов.
Имеется список из 53 человек. Необходимо выбрать из них победителя. Если вы выберете его самостоятельно, то вас могут обвинить в предвзятости. Поэтому вы решили написать программу. Она будет работать следующим образом. Вы вводите количество участников N , после чего программа выводит одно число – номер победителя.
Как получить число от игрока, вам уже известно. А вот как заставить компьютер загадать случайное число? В этом уроке вы этому научитесь.
Функция rand().
Данная функция возвращает случайное целое число в диапазоне от нуля до RAND_MAX . RAND_MAX это специальная константа языка Си, в которой содержится максимальное целое число, которое может быть возвращено функцией rand() .
Функция rand() определена в заголовочном файле stdlib.h . Поэтому, если хотите использовать rand в своей программе, не забудьте подключить этот заголовочный файл. Константа RAND_MAX тоже определена в этом файле. Вы можете найти этот файл у себя на компьютере и посмотреть её значение.
Давайте посмотрим на эту функцию в действии. Запустим следующий код:
Должно получиться что-то вроде этого.
Рис.1 Пять случайных чисел, сгенерированных функцийе rand
Но нам бы хотелось получить числа от 1 до 53 , а не всё подряд. Ниже описано несколько трюков, позволяющих наложить ограничения на функцию rand() .
Ограничить случайные числа сверху.
Кто в школе ждал момента, когда ему пригодится математика, приготовьтесь. Этот момент наступил. Чтобы ограничить сверху случайные числа, можно воспользоваться операцией получения остатка от деления, которую вы изучили в прошлом уроке. Наверное вы знаете, что остаток от деления на число K всегда меньше числа K . Например, при делении на 4 могут получиться остатки 0, 1, 2 и 3 . Поэтому если вы хотите ограничить сверху случайные числа числом K , то просто возьмите остаток от деления на K . Вот так:

Рис.2 Пять случайных чисел меньше 100
Ограничить числа снизу.
Функция rand возвращает случайные числа из отрезка [0, RAND_MAX] . А что если нам нужны только числа большие числа M (например, 1000 )? Как быть? Всё просто. Просто прибавим к тому, что вернула функция rand, наше значение M . Тогда если функция вернёт 0 , итоговый ответ будет M , если 2394 , то итоговый ответ будет M + 2394 . Этим действием мы как бы сдвигаем все числа на M единиц вперёд.
Задать границы функции rand сверху и снизу.
Например, получить числа от 80 до 100 . Кажется, нужно просто объединить два способа, которые приведены выше. Получим что-то вроде этого:
Попробуйте запустить эту программу. Удивлены?
Да, такой способ работать не будет. Давайте прокрутим эту программу руками, чтобы убедиться в том, что мы допустили ошибку. Допустим rand() вернула число 143 . Остаток от деления на 100 равен 43 . Дальше 80 + 43 = 123 . Значит такой способ не работает. Подобная конструкция выдаст числа от 80 до 179 .
Давайте разберём по действиям наше выражение. rand()%100 может выдать числа от 0 до 99 включительно. Т.е. из отрезка [0; 99] .
Операция + 80 сдвигает наш отрезок на 80 единиц вправо. Получаем [80; 179] .
Как видим, проблема у нас заключается в правой границе отрезка, она сдвинута вправо на 79 единиц. Это наше исходное число 80 минус 1 . Давайте наведём порядок и сдвинем правую границу назад: 80 + rand()%(100 — 80 + 1) . Тогда всё должно сработать как надо.
В общем случае если нам нужно получить числа из отрезка [A;B] , то необходимо воспользоваться следующей конструкцией:
A + rand()%(B-A+1) .
Согласно этой формуле перепишем нашу последнюю программу:
![Случайные числа из диапазона [80;100]](https://youngcoder.ru/lessons/4/rand_a_b.png)
Рис.3 Случайные числа из диапазона [80;100]
Ну вот, теперь вы можете решить исходную задачу урока. Сгенерировать число из отрезка [1; N] . Или не можете?
Но прежде ещё немного полезной информации. Запустите последнюю программу три раза подряд и записывайте себе случайные числа, которые она генерирует. Заметили?
Функция srand().
Да, каждый раз появляются одни и те же одинаковые числа. «Так себе генератор!» – скажете вы. И будете не совсем правы. Действительно, генерируются всё время одинаковые числа. Но мы можем на это повлиять, для этого используется функция srand() , которая также определена в заголовочном файле stdlib.h . Она инициализирует генератор случайных чисел начальным числом.
Скомпилируйте и запустите несколько раз вот эту программу:
Теперь поменяйте аргумент функции srand() на другое число (надеюсь вы ещё не забыли, что такое аргумент функции?) и снова скомпилируйте и запустите программу. Последовательность чисел должна измениться. Как только мы меняем аргумент в функции srand – меняется и последовательность. Не очень практично, не правда ли? Чтобы изменить последовательность, нужно перекомпилировать программу. Вот бы это число туда подставлялось автоматически.
И это можно сделать. Например, воспользуемся функцией time() , которая определена в заголовочном файле time.h . Данная функция, если ей в качестве аргумента передать NULL , возвращает количество секунд, прошедших c 1 января 1970 года . Вот посмотрите, как это делается.
Вы спросите, а что такое NULL ? Резонный вопрос. А я вам пока отвечу, что это специальное зарезервированное слово такое. Могу ещё сказать, что им обозначает нулевой указатель, но т.к. это для вас никакой информации не несёт, то на данный момент рекомендую об этом не думать. А просто запомнить как некоторый хитрый трюк. В будущих уроках мы остановимся на этой штуке поподробнее.
Сохрани в закладки или поддержи проект.
Практика
Решите предложенные задачи. Для удобства работы сразу переходите в полноэкранный режим 
Прототип функции rand:
Функция rand генерирует случайные числа, возвращает псевдослучайное целое число в диапазоне от 0 до RAND_MAX .
Это число генерируется алгоритмом, который возвращает последовательность псевдо-случайных чисел. Этот алгоритм использует своего рода «семя» — число, для создания серий случайных чисел. То есть, если семя всегда будет одно и то же, то сгенерированная последовательность чисел не будет меняться, исчезнет фактор стохастичности.
RAND_MAX это константа, определенная в <cstdlib> . По умолчанию её значение может изменяться, в зависимости от реализации, но, как правило, макрос RAND_MAX меньше значения 32767 не бывает.
Типичный способ генерации псевдослучайных чисел в определенном диапазоне с использованием функции rand выполняется следующим образом:
(value % 100) — генерация чисел в диапазоне от 0 до 99
(value % 100 + 1) — генерация чисел в диапазоне от 1 до 100
(value % 30 + 1985) — генерация чисел в диапазоне от 1985 до 2014
Однако, использование операции остаток от деления не создает поистине равномерно распределенных случайных чисел в заданном диапазоне, но, как правило, такой способ генерации чисел является хорошим приближением для небольших диапазонов.
Параметры:
Функция не принимает аргументов.
Возвращаемое значение
Целое псевдослучайное число в диапазоне от 0 до RAND_MAX .
Пример: исходный код программы
Пример работы программы
В этом примере, случайное зерно генерируется функцией time (функция time определена в заголовке <ctime> ). Использование данной функции — простой и достаточно хороший вариант генерации зерна.
Генерирование случайных чисел. Функции rand() , srand() , time() . Примеры
В языке C++ существуют средства для генерирования случайных чисел. Чтобы сгенерировать случайное число используется функция rand() , которая размещается в библиотечном файле stdlib.h . Синтаксис объявления функции следующий:
Функция возвращает случайное целочисленное значение, которое лежит в пределах от 0 до 32767.
Пример.
здесь startValue – целочисленное значение, которое служит отправной точкой для генерирования последовательности случайных чисел функцией rand() . Изменяя значение startValue , можно получать разные последовательности случайных чисел.
Пример.
то каждый раз при запуске программы будет создана новая отправная точка в генерировании последовательности чисел функцией rand() . И, как следствие, будут получаться разные последовательности случайных чисел.
Пример. В примере демонстрируется генерирование последовательности из двух случайных чисел. Каждый раз при запуске программы будет получена новая последовательность.
4. Как сгенерировать случайное целое число в заданных пределах? Пример
В примере приведена функция GetRandomNumber() , которая генерирует случайное число в заданных пределах.
5. Заполнение двумерной матрицы случайными целыми числами в указанных пределах. Пример
Условие задачи. Дана двумерная матрица порядка n ( n столбцов, n строк) целых чисел. Найти наибольшее из значений элементов, которые размещены в закрашенной части матрицы. Значение элементов матрицы формируются случайным образом и находятся в пределах [-5; +5].
Текст программы следующий
6. Как сгенерировать случайное число с плавающей запятой в указанных пределах? Пример
В примере демонстрируется функция GetRandomNumberFloat() , которая генерирует случайное число с плавающей запятой в указанных пределах.
Как работает rand c
Returns a pseudo-random integer value between 0 and RAND_MAX ( 0 and RAND_MAX included).
srand() seeds the pseudo-random number generator used by rand() . If rand() is used before any calls to srand() , rand() behaves as if it was seeded with srand ( 1 ) . Each time rand() is seeded with srand() , it must produce the same sequence of values.
rand() is not guaranteed to be thread-safe.
Contents
[edit] Parameters
[edit] Return value
Pseudo-random integer value between 0 and RAND_MAX , inclusive.
[edit] Notes
There are no guarantees as to the quality of the random sequence produced. In the past, some implementations of rand() have had serious shortcomings in the randomness, distribution and period of the sequence produced (in one well-known example, the low-order bit simply alternated between 1 and 0 between calls). rand() is not recommended for serious random-number generation needs, like cryptography.
POSIX requires that the period of the pseudo-random number generator used by rand be at least 2 32
.
POSIX offered a thread-safe version of rand called rand_r , which is obsolete in favor of the drand48 family of functions.