Как изменить генератор случайных чисел в C # при каждом вызове конструктора? - PullRequest
3 голосов
/ 21 января 2012

У меня есть два класса, класс Учителя и класс Студента. В моей программе я создаю массив из 10 объектов Учителя, и в каждом объекте Учителя есть массив из 10 объектов Учителя. Каждый объект Student также имеет массив целых чисел в качестве члена variabe, и когда создается экземпляр каждого Student, его собственный массив целых чисел заполняется числами из генератора случайных чисел. Моя программа выглядит примерно так:

  • Создан массив типа Учитель с размером 10
  • Массив затем заполняется 10 фактическими объектами учителя
  • Каждый объект Teacher содержит массив объектов Student размером 10 в качестве переменной-члена
  • Массив Student в каждом объекте Teacher заполнен фактическими объектами Student
  • Каждый объект студента имеет массив целых чисел, заполненных случайными числами в конструкторе объектов Студента.

Вот проблема, с которой я столкнулся: создается впечатление, что каждый раз, когда для каждого Учителя создаются 10 объектов Student, генератор случайных чисел в конструкторе объектов Student не сбрасывается и не изменяется даже при вызове функции .Next (). пока следующий набор из 10 объектов ученика не будет создан для следующего объекта Учителя. Я хочу, чтобы у каждого из 10 объектов Учителя были свои Студенческие объекты, у которых есть свои целые массивы, заполненные случайно сгенерированными числами.

Любая помощь будет принята с благодарностью! Я столкнулся с подобной проблемой с конструкторами в своем последнем вопросе, и это было вопросом того, должно ли что-то быть статичным или нет, и я не уверен, что так на этот раз. Пожалуйста, задавайте мне вопросы, если я не был достаточно ясен ни о чем !!

ОБНОВЛЕНИЕ ** Поэтому, посмотрев на MSDN, я нашел в их примере код «Thread.Sleep (2000)» и вставил его в конструктор Student, чтобы посмотреть, что он сделал. Казалось, что это решило проблему, хотя моя программа теперь работает намного медленнее, есть ли минимальное значение ожидания для ожидания, пока Random.Next () использует новое начальное число от часов, и даже если я действительно решил проблему, есть ли лучший способ сделать это? Мой генератор случайных чисел уже является статической переменной-членом Student.

Ответы [ 3 ]

5 голосов
/ 21 января 2012

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

for (int i = 0; i < 1000; i++) {
   var random = new Random();
   list.Add(random.Next());
}

Это не работает должным образом, поскольку Random использует фактическое время для созданияпервое случайное значение.Тем не менее, часы имеют ограниченное разрешение.Может быть так, что несколько последовательных итераций возвращают одно и то же время и, следовательно, одно и то же (псевдо) случайное значение!

Решение состоит в том, чтобы создать random только один раз.объявить random статическим членом класса

public static readonly Random RandomGenerator = new Random();
5 голосов
/ 21 января 2012

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

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

public class Student
{
    private static readonly Random random = new Random();        
}

Со страницы MSDN в конструкторе Random () :

Начальное значение по умолчанию получено из системных часов и имеет конечное разрешение.В результате различные Random объекты, созданные в тесной последовательности при вызове конструктора по умолчанию, будут иметь идентичные начальные значения по умолчанию и, следовательно, будут создавать идентичные наборы случайных чисел.Этой проблемы можно избежать, используя один объект Random для генерации всех случайных чисел.Вы также можете обойти это, изменив начальное значение, возвращаемое системными часами, и затем явно предоставив это новое начальное значение конструктору Random(Int32).Для получения дополнительной информации см. Конструктор Random(Int32).

Редактировать : хотя вы заявляете, что генератор случайных чисел уже является статическим членом, этовсе еще недостаточно, если вы создаете его повторно (избыточно) во время каждой Student инициализации.Следующий код по-прежнему неверен :

public class Student
{
    private static Random random;

    private int[] numbers;

    public Student()
    {
        random = new Random();
        numbers = new int[10];
        for (int i = 0; i < 10; ++i)
            numbers[i] = random.Next();
    }
}

Вам необходимо заменить его на версию, в которой экземпляр Random создается только один раз, например:

public class Student
{
    private static readonly Random random = new Random();

    private int[] numbers;

    public Student()
    {
        numbers = new int[10];
        for (int i = 0; i < 10; ++i)
            numbers[i] = random.Next();
    }
}
1 голос
/ 21 января 2012

Генератор случайных чисел использует системное время в качестве начального числа. Интересно, возможно, вы объявляете новый генератор и вызываете его до того, как система успеет перейти к следующему приращению? Циклы процессора на самом деле более чем часто быстрее системных часов. Можете опубликовать пример кода?

Я бы предложил объявить Статический генератор либо как свойство класса, либо как-нибудь еще доступным, создать его экземпляр как final. Это гарантирует, что вы не будете перезаписывать генератор другим.

...