Мне нужно семя для экземпляра класса C # Random, и я читал, что большинство людей используют для этого счетчик тиков текущего времени. Но это 64-битное значение, и начальное значение должно быть 32-битным. Теперь я подумал, что метод GetHashCode(), который возвращает int, должен предоставлять разумно распределенное значение для своего объекта, и это можно использовать, чтобы избежать использования только младших 32 бита счетчика тиков. Однако я не смог найти ничего о GetHashCode () для типа данных Int64.

Итак, я знаю, что это не имеет большого значения, но будет ли следующая работа работать так же хорошо, как я думаю (я не могу использовать случайность методом проб и ошибок), или, может быть, она работает так же, как использование (int)DateTime.Now.Ticks в качестве начального числа ? А может еще хуже работает? Кто может пролить свет на это.

int seed = unchecked(DateTime.Now.Ticks.GetHashCode());
Random r = new Random(seed);

Изменить: зачем мне семя и не позволять конструктору Random() делать свою работу? Мне нужно отправить семя другим клиентам, которые используют то же семя для той же случайной последовательности.

16
Daniel A.A. Pelsmaeker 31 Окт 2010 в 02:31
2
Вы забыли написать свой действительно хороший аргумент в пользу того, что вам нужно семя.
 – 
Claus Jørgensen
31 Окт 2010 в 02:33
2
Что ж, теперь я добавил этот действительно хороший аргумент . :)
 – 
Daniel A.A. Pelsmaeker
31 Окт 2010 в 02:30

3 ответа

Лучший ответ

new Random() уже использует текущее время. Это эквивалентно new Random(Environment.TickCount).

Но это деталь реализации, которая может измениться в будущих версиях .net.

Я бы рекомендовал использовать new Random () и предоставлять фиксированное начальное число только в том случае, если вы хотите получить воспроизводимую последовательность псевдослучайных значений.

Поскольку вам нужно известное семя, просто используйте Environment.TickCount, как это делает MS. А затем передать его другим экземплярам программы в качестве начального числа.

Если вы создаете несколько экземпляров Random за короткий интервал (может быть 16 мс), они могут быть засеяны до одного и того же значения и, таким образом, создать одну и ту же псевдослучайную последовательность. Но это, скорее всего, не проблема. Эта распространенная ошибка возникает из-за того, что окна обновляют текущее время (DateTime.Now / .UtcNow) и TickCount (Environment.TickCount) только каждые несколько миллисекунд. Точный интервал зависит от версии Windows и других запущенных программ. Типичные интервалы, когда они не меняются, составляют 16 мс или 1 мс.

34
CodesInChaos 14 Апр 2011 в 02:34
2
+1 за упоминание о том, что единственный раз, когда действительно нужно предоставить собственное начальное значение, - это когда вы хотите воспроизвести определенную последовательность значений. Подумайте о вариантах пасьянса Windows «номер игры».
 – 
Andrew Barber
31 Окт 2010 в 02:25
Я отредактировал свой вопрос. Я знаю о конструкторе new Random(), но мне нужно семя.
 – 
Daniel A.A. Pelsmaeker
31 Окт 2010 в 02:30
Или, если вы повторяете метод / блок за пределами генерации Random, вам нужны уникальные начальные числа и вы хотите избежать риска коллизий из-за недостаточного разрешения по времени, как пишет CodesInChaos.
 – 
Alex
5 Июн 2014 в 07:25
Я почти уверен, что CodeInChaos говорит не об этом. Я цитирую: «Предоставляйте фиксированное начальное число только в том случае, если вы хотите получить воспроизводимую последовательность ... значений». Вам не следует создавать так много случайных экземпляров.
 – 
Andrew Barber
5 Июн 2014 в 07:30
1
Я думал о том же самом;) Я думаю, вы это понимаете, но я просто думаю, что между нами есть какие-то мелкие технические детали или что-то такое! Бедный CodeInChaos будет удивляться, почему его ответ взорвался! ;)
 – 
Andrew Barber
5 Июн 2014 в 09:49

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

Random random = new Random(Guid.NewGuid().GetHashCode());
31
steinar 31 Окт 2010 в 02:38
3
И почему это может быть лучше, чем DateTime.Now.Ticks.GetHashCode()?
 – 
Daniel A.A. Pelsmaeker
31 Окт 2010 в 02:31
17
Это лучше, потому что он не страдает той проблемой, что DateTime.Now изменяется только каждые несколько миллисекунд. При использовании этого метода очень маловероятно, что два экземпляра random получат одно и то же начальное число даже при быстрой инициализации.
 – 
CodesInChaos
13 Июн 2011 в 16:10
1
А вы уверены, что хеш-коллизий нет?
 – 
oɔɯǝɹ
17 Апр 2013 в 19:17
1
В точности то, что написано в oɔɯǝɹ - вероятно, их было бы меньше, если бы вы просто использовали GUID. stackoverflow.com/questions/7326593/guid-gethashcode-uniqueness
 – 
bbill
25 Июн 2013 в 01:46
1
Этот подход будет случайным образом взорваться каждый раз, когда gethashcode вернет int.minvalue из-за случайного выполнения abs для семени и abs взрыва на int.minvalue. Вместо этого вам нужно сделать это ... Random random = new Random(Guid.NewGuid().GetHashCode() & int.MaxValue); Чтобы убедиться, что вы отправляете только положительные целые числа.
 – 
Ramon Leon
29 Мар 2017 в 02:08

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

Итак, вот мое решение.

    int TOTALQ = 7;
    int NOOFQ = 5;

    int[] selectedQuestion = new int[TOTALQ];

    int[] askQuestion = new int[NOOFQ];

    /*   Genarae a random number 1 to TOTALQ
     *   - if that number in selectedQuestion array is not o
     *   -     Fill askQuestion array with that number
     *   -     remove that number from selectedQuestion
     *   - if not re-do that - - while - array is not full.    
     */

    for (int i = 0; i < TOTALQ; i++)  // fill the array
        selectedQuestion[i] = 1;

    int question = 0;

    int seed = 1;

    while (question < NOOFQ)
    {       
        DateTime now1 = new DateTime();
        now1 = DateTime.Now;    
        Random rand = new Random(seed+now1.Millisecond);
         int RandomQuestion = rand.Next(1, TOTALQ);

         Response.Write("<br/> seed  " + seed + " Random number " + RandomQuestion );



        if (selectedQuestion[RandomQuestion] != 0)      
        {
            selectedQuestion[RandomQuestion] = 0;  // set that q =0 so not to select           
            askQuestion[question] = selectedQuestion[RandomQuestion];
            Response.Write(".  Question no " + question + " will be question " + RandomQuestion + " from list " );
            question++;
        }

        seed++;         

    }
0
Saman 20 Сен 2014 в 05:47