Генерация случайных чисел в C#
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Генерация случайных чисел является неотъемлемой и важной частью многих криптографических операций. Например, криптографические ключи должны выбираться настолько случайно, насколько это, в принципе, возможно. В .NET C# есть несколько вариантов генерации случайных чисел.
Класс Random
Этот класс представляет генератор псевдослучайных чисел. То есть, в работе этого класса заложен алгоритм, который генерирует последовательность чисел, отвечающую определенным статистическим критериям случайности.
Конструкторы класса Random
У класса определено два конструктора. Первый конструктор — без параметров, создает новый экземпляр класса и инициализирует его значением по умолчанию. В .NET Framework начальное значение по умолчанию зависит от текущего времени. В .NET Core и более поздних версиях платформы начальное значение по умолчанию создается генератором псевдослучайных чисел потока. Конструктор без параметров используется наиболее часто и позволяет создавать генераторы случайных чисел с оптимальной производительностью и вероятностью распределения случайной величины. Например, так мы можем создать экземпляр Random , используя этот конструктор:
Второй конструктор позволяет создавать новый экземпляр Random и инициализировать его заданным значением, например
Random rnd1 = new Random(100);
Этот конструктор стоит использовать в том случае, если Вам необходимо получать каждый раз одну и ту же серию псевдослучайных чисел, например, для отладки приложения. Чтобы продемонстрировать наглядно, что имеется в виду, напишем следующий пример:
byte[] bytes1 = new byte[5]; Random rnd1 = new Random(); rnd1.NextBytes(bytes1); for (int ctr = bytes1.GetLowerBound(0); ctr ", bytes1[ctr]); if ((ctr + 1) % 10 == 0) Console.WriteLine(); >
здесь мы создаем массив из пяти псевдослучайных байтов и выводим его в консоль. Вот, что мы можем увидеть, если перезапустим наше приложение, скажем, 3 раза:
Три запуска — три различных серии случайных чисел. Теперь воспользуемся конструктором с начальным значением и также попытаемся сформировать три серии случайных чисел:
Random rnd1 = new Random(100); //тут тот же код, что и в примере выше
Три запуска — три серии одинаковых чисел.
Вот, собственно, наглядная демонстрация того, чем принципиально отличаются конструкторы у 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#
byte[] bytes = new byte[100];//создаем массив на 100 элементов Random rnd = new Random(); //создаем объект класса rnd1.NextBytes(bytes);//генерация 100 случайных байтов
или, если необходимо получить одно случайное число, то можно воспользоваться методами Next :
int a = rnd1.Next(); //случайное целое число int b = rnd1.Next(100);//случайное целое число меньше 100 int c = rnd1.Next(-100, 100); //случайное число от -100 до 100 Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(c);
Если вы планируете использовать объекты класса Random в потоках, то необходимо использовать потокобезопасный экземпляр, используя свойство Shared класса, например, так:
Random threadSafeRnd = 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) | Заполняет диапазон криптостойкими случайными байтами. |
Get Bytes(Int32) | Создает массив байтов с криптографически строгой случайной последовательностью значений. |
Get Int32(Int32) | Создает случайное целое число от 0 (включительно) до указанного исключенного верхнего предела, используя генератор криптостойких случайных чисел. |
Get Int32(Int32, Int32) | Создает случайное целое число от указанного нижнего предела (включенного ) до указанного верхнего предела (исключая его), используя генератор криптостойких случайных чисел. |
Примеры использования этих методов представлены ниже:
Span bytes = new Span(bytes1); RandomNumberGenerator.Fill(bytes); bytes2 = RandomNumberGenerator.GetBytes(bytes2.Length); int a = RandomNumberGenerator.GetInt32(100); //случайное число до 100 int b = RandomNumberGenerator.GetInt32(-100, 100); //случайное число от -100 до 100
Проблемы с RandomNumberGenerator
RandomNumberGenerator использует более сложные алгоритмы для генерации случайных чисел и их последовательностей, а за качество нам приходится «платить» скоростью. Поэтому при прочих равных условиях RandomNumberGenerator будет работать всегда медленнее, чем Random . Ниже в таблице, для примера, показано время в миллисекундах которое потребовалось двум генераторам для генерации 1000 000 случайных величин
# цикла | Random | RandomNumberGenerator |
---|---|---|
1 | 9 | 187 |
2 | 10 | 184 |
3 | 9 | 182 |
Итого
Для генерации случайных чисел в C# могут использоваться два класса — Random и RandomNumberGenerator . При этом, класс Random обладает большей производительностью, однако, является менее надежным, чем RandomNumberGenerator , который использует более сложные алгоритмы генерации случайных величин и используется в работе алгоритмов шифрования.
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.