Создание истинного случайного

Возможный дубликат:
Почему кажется, что мой генератор случайных чисел не является случайным в С#?
Как я могу генерировать поистине (не псевдо) случайные числа с помощью С#?

Я создал игру в кости, в которой кости основаны на процентиле, 1-100.

public static void Roll()
{
    Random rand = new Random((int)DateTime.Now.Ticks);
    return rand.Next(1, 100);
}

Но я не чувствую себя настоящим случайным, основанным на текущем времени.

Если я делаю

for (int i = 0; i < 5; i++)
{
   Console.WriteLine("#" + i + " " + Roll());
}

Все они будут одинаковыми значениями, потому что DateTime.Now.Ticks не изменился, он засеял тот же номер.

Я думал, что могу генерировать новое случайное семя, если семя было таким же из-за текущего времени, но оно не похоже на честный "повторный ролл"

Что мне делать, чтобы попытаться скопировать близкий к реальному/честному рулону? Должен ли я использовать класс RNGCryptoServiceProvider для генерации рулонов вместо?

Ответ 1

DateTime.Now.Ticks имеет разрешение примерно 16 мс, поэтому, если вы создаете Random с такой перегрузкой несколько раз в течение 16 мс "слот" все они будут высеваться с одинаковым значением, и поэтому вы получите одну и ту же последовательность.

Инициализируйте свой Random вне вашего цикла, чтобы создать одиночную последовательность Random, а не создавать ее каждый раз в цикле, что может привести к тому, что Randoms будет засеян одним и тем же значением и, таким образом, приведет к той же последовательности.

Обновление

Моя предыдущая мысль о том, что конструктор по умолчанию, инициализированный Random с тиками ЦП, был неправильным, конструктор по умолчанию фактически использует Environment.TickCount, который

32-разрядное целое число со знаком, содержащее время в миллисекундах, прошедшее с момента последнего запуска компьютера.

Которая все еще имеет низкое разрешение. Если вы делаете несколько экземпляров Random в быстрой последовательности, их можно легко создать в одном и том же временном интервале и, следовательно, иметь одинаковое начальное значение и создать одну и ту же последовательность. Создайте один экземпляр Random и используйте его.

Обновление

В дополнение к вашим комментариям, если вы хотите создать случайную последовательность для нескольких потоков, см. следующую статью Jon Skeet, в которой обсуждается потокобезопасная оболочка:

https://codeblog.jonskeet.uk/2009/11/04/revisiting-randomness

Ответ 2

Генераторы псевдослучайных чисел, такие как Random, должны быть посещены один раз, поэтому:

private static Random _rand = new Random();
public static int Roll()
{
    return _rand.Next(1, 100);
}

(Примечание. Я сделал возвращаемое значение int, а не void, функция Roll, указанная в вопросе, приводит к ошибке синтаксиса.)

Но ваш заголовок говорит "Создание истинного случайного". Random не сделает этого для вас, это псевдослучайный генератор чисел, означающий, что он детерминирован, просто трудно предсказать, Знать семя. Обычно это достаточно хорошо для большинства целей, но если вам нужна реальная случайность, вам нужен источник энтропии. http://random.org является одним из популярных.

Ответ 3

Вы должны создать класс Random только один раз за пределами функции Roll и занести его с уникальным значением.

Вы воссоздаете свой случайный каждый раз, когда вы вызываете Roll, который вызывает "не случайные числа".

Ответ 4

Должен ли я использовать класс RNGCryptoServiceProvider для генерации роликов?

Если это серьезная игра с деньгами на карту, то: Да.

Ответ 5

Я предполагаю, что вы вызываете метод Roll() так быстро, что Now.Ticks - то же самое?

Самый простой способ, чтобы обойти это было бы вместо того, чтобы создать новый объект Random() экземпляру каждый раз, когда вы вызываете Roll() создать статическую переменную для хранения одного экземпляра Random().

Ответ 6

Обычный способ использования генераторов случайных чисел состоит в том, чтобы засеять их один раз, сохранить их и называть их неоднократно в вашей программе. Пока вы начинаете с подходящего значения в начале, вы должны получить приемлемую случайность - если генератор, который вы используете, использует функцию, возвращающую вещи, которые являются случайными для ваших целей. Итак, сохраните экземпляр Random вне функции Roll(), запустите его при первом использовании, а затем просто вызовите Next() на нем каждый раз, когда вам понадобится другой номер.

Когда вы справляетесь с этим, на компьютере нет такой вещи, как создание истинных случайных чисел, а только псевдослучайные последовательности, основанные на семени. Однако люди страшны при определении случайности, поэтому обычно это нормально.