Генерация случайных чисел в языке Си
Иногда может возникнуть необходимость в генерации случайных чисел. Простой пример.
Пример: Определение победителя в конкурсе репостов.
Имеется список из 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() , srand() , time() . Примеры
В языке C++ существуют средства для генерирования случайных чисел. Чтобы сгенерировать случайное число используется функция rand() , которая размещается в библиотечном файле stdlib.h . Синтаксис объявления функции следующий:
Функция возвращает случайное целочисленное значение, которое лежит в пределах от 0 до 32767.
Пример.
здесь startValue – целочисленное значение, которое служит отправной точкой для генерирования последовательности случайных чисел функцией rand() . Изменяя значение startValue , можно получать разные последовательности случайных чисел.
Пример.
то каждый раз при запуске программы будет создана новая отправная точка в генерировании последовательности чисел функцией rand() . И, как следствие, будут получаться разные последовательности случайных чисел.
Пример. В примере демонстрируется генерирование последовательности из двух случайных чисел. Каждый раз при запуске программы будет получена новая последовательность.
4. Как сгенерировать случайное целое число в заданных пределах? Пример
В примере приведена функция GetRandomNumber() , которая генерирует случайное число в заданных пределах.
5. Заполнение двумерной матрицы случайными целыми числами в указанных пределах. Пример
Условие задачи. Дана двумерная матрица порядка n ( n столбцов, n строк) целых чисел. Найти наибольшее из значений элементов, которые размещены в закрашенной части матрицы. Значение элементов матрицы формируются случайным образом и находятся в пределах [-5; +5].
Текст программы следующий
6. Как сгенерировать случайное число с плавающей запятой в указанных пределах? Пример
В примере демонстрируется функция GetRandomNumberFloat() , которая генерирует случайное число с плавающей запятой в указанных пределах.
Как генерировать случайные числа в C#
Мы можем использовать класс Random для генерации случайных чисел в C#.
Что такое класс C# Random ? #
C# Random class — это генератор псевдослучайных чисел, который представляет собой алгоритм, генерирующий последовательность чисел, отвечающих определенным статистическим требованиям к случайности.
Этот класс имеет 5 методов Next() , NextInt64() , NextBytes() , NextDouble() и NextSingle()
В зависимости от типа числа, т.е. int , long и т.д., мы можем использовать соответствующий метод.
Давайте рассмотрим примеры, чтобы понять это дальше
Генерация случайного целого числа в C# #
Шаги для генерации случайного целого числа в C#
- Инстанцируйте класс случайных чисел.
- Используйте метод Random.Next() , чтобы вернуть случайное целое число между Int32.MinValue и Int32.MaxValue .
Генерируем случайное целое число между минимальным и максимальным значениями #
Random.Next() имеет перегруженный метод, принимающий в качестве параметров минимальное и максимальное значения, который генерирует случайное целое число между заданными значениями.
Для генерации случайных чисел от 100 до 1000 используйте следующий код
Генерация случайного длинного числа(Int64) в C# #
Для генерации случайного длинного числа Int64 в C# используйте метод Random.NextInt64() , который возвращает случайное число Int64 между Int64.MinValue и Int64.MaxValue .
Генерирование случайного длинного числа(Int64) в заданном диапазоне #
Как и Random.Next() , Random.NextInt64() имеет перегруженный метод, который принимает Range, т.е. минимальное и максимальное значения в качестве параметров, и возвращает случайное число Int64 между ними.
Для генерации случайных чисел в диапазоне от 100000 до 200000 используйте следующий код
Сгенерированные случайные числа не являются полностью случайными, поскольку для их выбора используется математический алгоритм, но они достаточно хороши для большинства реальных случаев.
Избегание дубликатов при генерации случайных чисел #
Если вы инициализируете более одного класса new Random()
Вы можете получить дубликаты случайных чисел. (Многопоточное приложение)
Поэтому лучше инициализировать только один экземпляр класса Random() и использовать его во всем приложении.
Если вы хотите генерировать серию случайных чисел, в многопоточной среде используйте вышеуказанный метод.
Использование криптографических C# RandomNumberGenerator #
Если вы хотите генерировать действительно уникальные случайные числа, вы можете воспользоваться классом RandomNumberGenerator , который является частью библиотеки System.Security.Cryptography .
Этот класс генерирует криптографически защищенное случайное число и подходит для создания случайного пароля.
Мы также можем передать диапазон в метод RandomNumberGenerator .
Использование класса C# RNGCryptoServiceProvider #
Этот класс уже устарел, не используйте этот метод.
RNGCryptoServiceProvider реализует криптографический генератор случайных чисел (ГСЧ), используя реализацию, предоставленную поставщиком криптографических услуг (CSP).
Используйте приведенный ниже код для создания случайного числа с помощью класса C# RNGCryptoServiceProvider .
Summary #
В этом уроке мы изучили различные способы генерации случайных чисел в C# на простых примерах.
Don’t be a Stranger. Connect me at Social Networking Sites.
Stay in the loop
Get a short & sweet tutorials delivered to your inbox every couple of days. No spam ever. Unsubscribe any time.
Генерация случайных чисел в C#
Генерация случайных чисел является неотъемлемой и важной частью многих криптографических операций. Например, криптографические ключи должны выбираться настолько случайно, насколько это, в принципе, возможно. В .NET C# есть несколько вариантов генерации случайных чисел.
Класс Random
Этот класс представляет генератор псевдослучайных чисел. То есть, в работе этого класса заложен алгоритм, который генерирует последовательность чисел, отвечающую определенным статистическим критериям случайности.
Конструкторы класса Random
У класса определено два конструктора. Первый конструктор — без параметров, создает новый экземпляр класса и инициализирует его значением по умолчанию. В .NET Framework начальное значение по умолчанию зависит от текущего времени. В .NET Core и более поздних версиях платформы начальное значение по умолчанию создается генератором псевдослучайных чисел потока. Конструктор без параметров используется наиболее часто и позволяет создавать генераторы случайных чисел с оптимальной производительностью и вероятностью распределения случайной величины. Например, так мы можем создать экземпляр Random , используя этот конструктор:
Второй конструктор позволяет создавать новый экземпляр Random и инициализировать его заданным значением, например
Этот конструктор стоит использовать в том случае, если Вам необходимо получать каждый раз одну и ту же серию псевдослучайных чисел, например, для отладки приложения. Чтобы продемонстрировать наглядно, что имеется в виду, напишем следующий пример:
здесь мы создаем массив из пяти псевдослучайных байтов и выводим его в консоль. Вот, что мы можем увидеть, если перезапустим наше приложение, скажем, 3 раза:
Три запуска — три различных серии случайных чисел. Теперь воспользуемся конструктором с начальным значением и также попытаемся сформировать три серии случайных чисел:
Три запуска — три серии одинаковых чисел.
Вот, собственно, наглядная демонстрация того, чем принципиально отличаются конструкторы у Random .
Методы и свойства Random
Чтобы сгенерировать случайное число, у класса Random предусмотрены следующие методы:
| Метод | Описание |
|---|---|
| Next() | Возвращает неотрицательное случайное целое число. |
| Next(Int32) | Возвращает неотрицательное случайное целое число, которое меньше указанного максимального значения. |
| Next(Int32, Int32) | Возвращает случайное целое число в указанном диапазоне. |
| Next Bytes(Byte[]) | Заполняет элементы указанного массива байтов случайными числами. |
| Next Double() | Возвращает случайное число с плавающей запятой, которое больше или равно 0,0 и меньше 1,0. |
| NextSingle() | Возвращает случайное число с плавающей запятой в диапазоне от 0,0 до 1,0. |
Пример использования класса Random в приложениях C#
или, если необходимо получить одно случайное число, то можно воспользоваться методами Next :
Если вы планируете использовать объекты класса Random в потоках, то необходимо использовать потокобезопасный экземпляр, используя свойство Shared класса, например, так:
Проблемы с Random
По данным разработчиков, в большинстве систем Windows объекты Random , созданные с интервалом в 15 миллисекунд друг от друга, скорее всего, будут иметь одинаковые начальные значения. Возможно, что это утверждение относится только к .NET Framework (или же информация на сайте Microsoft устарела), так как для .NET 7 пример этой проблемы, предоставленный самой Microsoft, у меня показывал абсолютно различные ряды случайных чисел, несмотря на соблюдение всех условий — создание двух экземпляров Random в течение 15 мс и менее, ряд на 100 элементов и т.д.
Класс RandomNumberGenerator
Этот класс расположен в пространстве имен System.Security.Cryptography и предназначен для создания криптографически надежных случайных значений. Класс абстрактный, поэтому создавать напрямую мы его не можем, но можем использовать классы, его реализующие, например, классом RNGCrypto Service Provider , который на данный момент не рекомендуется использовать или же, как рекомендуют разработчики из Microsoft — использовать статические методы класса. Посмотрим как работает RandomNumberGenerator .
Статические методы RandomNumberGenerator
Если не создавать наследника для RandomNumberGenerator , то для генерации случайных чисел мы можем воспользоваться следующими статическими методами класса:
| Метод | Описание |
|---|---|
| Create() | Создает экземпляр реализации по умолчанию криптографического генератора случайных чисел, позволяющего генерировать случайные данные. |
| Fill(Span<Byte>) | Заполняет диапазон криптостойкими случайными байтами. |
| Get Bytes(Int32) | Создает массив байтов с криптографически строгой случайной последовательностью значений. |
| Get Int32(Int32) | Создает случайное целое число от 0 (включительно) до указанного исключенного верхнего предела, используя генератор криптостойких случайных чисел. |
| Get Int32(Int32, Int32) | Создает случайное целое число от указанного нижнего предела (включенного ) до указанного верхнего предела (исключая его), используя генератор криптостойких случайных чисел. |
Примеры использования этих методов представлены ниже:
Проблемы с RandomNumberGenerator
RandomNumberGenerator использует более сложные алгоритмы для генерации случайных чисел и их последовательностей, а за качество нам приходится «платить» скоростью. Поэтому при прочих равных условиях RandomNumberGenerator будет работать всегда медленнее, чем Random . Ниже в таблице, для примера, показано время в миллисекундах которое потребовалось двум генераторам для генерации 1000 000 случайных величин
| # цикла | Random | RandomNumberGenerator |
|---|---|---|
| 1 | 9 | 187 |
| 2 | 10 | 184 |
| 3 | 9 | 182 |
Итого
Для генерации случайных чисел в C# могут использоваться два класса — Random и RandomNumberGenerator . При этом, класс Random обладает большей производительностью, однако, является менее надежным, чем RandomNumberGenerator , который использует более сложные алгоритмы генерации случайных величин и используется в работе алгоритмов шифрования.