Наверняка, всем известно о существовании в .Net класса System.Random, позволяющего получать якобы случайные числа практически без особых как умственных, так и временных затрат. Представьте что у нас есть такой вот метод, который чисто ради эксперимента мы вызовем в цикле несколько раз:
static string GetRandomNum(int minValue, int maxValue) { Random rnd = new Random(); return rnd.Next(minValue, maxValue).ToString(); } for (int i = 0; i < 10; i++) { Console.WriteLine(GetRandomNum(1,11)); }
В данном случае вы получите совершенно одинаковые все "случайные" цифры.
Происходит так потому, что при инициализации объекта Random с использованием конструктора по умолчанию в качестве числа, использующегося для вычисления случайных чисел используется Environment.TickCount (количество миллисекунд, прошедших со времени старта системы), который обновляется раз в 15.6 миллисекунд.
Соответственно, на коротких интервалах и получаются одинаковые "случайные" числа. И, кстати, если каждый день включать компьютер в одно и то же время, то выполняя этот код в одно и то же время с начала старта операционной системы в течении нескольких дней, вы тоже будете получать одни и те же потрясающе случайные значения. И если в рамках одного периода включения-выключения компьютера с этим можно бороться путем создания и инициализации объекта класса Random один раз, то с тем, что значения будут совсем довольно предсказуемы в рамках нескольких дней в Random сделать ничего нельзя.
Для получения гарантированно значительно более случайных и предсказуемых чисел в .Net существует класс RNGCryptoServiceProvider, находящийся в пространстве имен System.Security.Cryptography, в котором нас интересует метод GetBytes(byte[] data), заполняющий массив байтом криптостойкой случайной последовательностью чисел. Но как же с помощью него получить, то, что мы получали от Random, а именно случайное число, находящееся между двумя заданными значениями?
Сделать это довольно просто, если представить полученный случайный байт как число из диапазона от 0 до 1, и произвести с ним несложные математические действия:
static string GetRandomNum(int minValue, int maxValue) { System.Security.Cryptography.RNGCryptoServiceProvider rnd = new System.Security.Cryptography.RNGCryptoServiceProvider(); //Получаем наш случайный байт byte[] randombyte = new byte[1]; rnd.GetBytes(randombyte); //превращаем его в число от 0 до 1 double random_multiplyer = (randombyte[0] / 255d); //получаем разницу между минимальным и максимальным значением int difference = maxValue-minValue+1; //прибавляем к минимальному значение число от 0 до difference int result = (int)(minValue + Math.Floor(random_multiplyer * difference)); return result.ToString(); }
В результате выполнения этого кода последовательность чисел будет уже, во-первых, более разнообразной, а, во-вторых, она будет действительно случайной.
Автор, данный метод выдает на 1 значение больше максимального. Прошу это проверить.
ОтветитьУдалить