Почему не случайно () случайно?

Возможный дубликат:
Почему этот генератор случайных чисел не случайный?

У меня есть эта тестовая программа:

static void Main(string[] args)
{
    var randomNumbers = new Dictionary<int, int>();
    foreach (var s in Enumerable.Range(1, 500))
    {
        var rand = Rand5();
        if (!randomNumbers.ContainsKey(rand))
            randomNumbers.Add(rand, 1);
        else
            randomNumbers[rand] += 1;
    }

    randomNumbers
        .ToList()
        .ForEach(x => Console.WriteLine("{0}: {1}", x.Key, x.Value));
    Console.ReadLine();
}

static int Rand5()
{
    System.Threading.Thread.Sleep(1);
    return new Random().Next(1, 6);
}



Если я закомментирую System.Threading.Thread.Sleep(1);, Я получил

5: 500

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

2: 87
4: 94
1: 116
5: 108
3: 95

Почему строка кода имеет значение? Спасибо!

6 ответов

Решение

Как уже говорили другие, new Random() запускает генератор случайных чисел из текущего системного времени.

У меня есть статья, описывающая это более подробно, включая решения проблемы, которые вы можете найти полезными. В основном вы хотите использовать тот же экземпляр Random несколько раз - но заметив, что это не потокобезопасно.

Random Тип определяется по умолчанию в соответствии с текущим системным временем, которое имеет конечную гранулярность.

призвание new Random().Next(1, 6) много раз в быстрой последовательности, таким образом, построит много Random объекты с одинаковым начальным значением, дающие одинаковый результат. Thread.Sleep(1) Вызов "решает" эту проблему, просто разнося конструкции дальше друг от друга во времени, увеличивая вероятность различных начальных значений.

Вы должны сохранить определенный Random объект от одного звонка до следующего:

var randomNumbers = new Dictionary<int, int>();
var random = new Random(); // Re-use this, don't keep creating new ones.
foreach (var s in Enumerable.Range(1, 500))
{
    var rand = random.Next(1, 6);
    // ...

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

Генератор случайных чисел частично основан на системных часах, и C# слишком чертовски быстро их производит...

Если вы не запустили случайное число, вы получите то же число, что и Random - генератор псевдослучайных чисел.

Используя Thread.Sleep(1), вы позволяете таймеру продвигаться и генерировать новое автоматически сгенерированное семя.

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

Более подробная информация на http://msdn.microsoft.com/en-us/library/ctssatww.aspx

Любой генератор случайных чисел, который вы используете, является псевдослучайным числом. Это всегда будет иметь заранее определенное начальное значение и хорошо для тестирования, но не для реализации функций истинной случайности.

Вы должны использовать последовательность квазислучайных чисел для генерации случайных чисел или, что еще лучше, цепочку Маркова для генерации лучших случайных чисел. Если вы планируете использовать одну из этих функций Random, у вас не будет ничего похожего на настоящую случайность.

Другие вопросы по тегам