Seeding a pseudo-random number generator in C#

2019-01-19 10:42发布

I need a seed for an instance of C#'s Random class, and I read that most people use the current time's ticks counter for this. But that is a 64-bit value and the seed needs to be a 32-bit value. Now I thought that the GetHashCode() method, which returns an int, should provide a reasonably distributed value for its object and this may be used to avoid using only the lower 32-bits of the tick count. However, I couldn't find anything about the GetHashCode() of the Int64 datatype.

So, I know that it will not matter much, but will the following work as good as I think (I can't trial-and-error randomness), or maybe it works the same as using (int)DateTime.Now.Ticks as the seed? Or maybe it even works worse? Who can shed some light on this.

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

Edit: Why I need a seed and don't just let the Random() constructor do the work? I need to send the seed to other clients which use the same seed for the same random sequence.

3条回答
兄弟一词,经得起流年.
2楼-- · 2019-01-19 11:21

I had a similar question , to select a random set of questions from a larger list of questions. But when I use the time as the seed it gives the same random number .

So here is my solution.

    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++;         

    }
查看更多
趁早两清
3楼-- · 2019-01-19 11:39

new Random() already uses the current time. It is equivalent to new Random(Environment.TickCount).

But this is an implementation detail and might change in future versions of .net

I'd recommend using new Random() and only provide a fixed seed if you want to get a reproducible sequence of pseudo random values.

Since you need a known seed just use Environment.TickCount just like MS does. And then transmit it to the other program instances as seed.

If you create multiple instances of Random in a short interval (could be 16ms) they can be seeded to the same value, and thus create the same pseudo-random sequence. But that's most likely not a problem here. This common pitfall is caused by windows updating the current time(DateTime.Now/.UtcNow) and the TickCount(Environment.TickCount) only every few milliseconds. The exact interval depends on the version of windows and on what other programs are running. Typical intervals where they don't change are 16ms or 1ms.

查看更多
闹够了就滚
4楼-- · 2019-01-19 11:47

If you need to seed it with something other than the current time (in which case you can use the default constructor), you can use this:

Random random = new Random(Guid.NewGuid().GetHashCode());
查看更多
登录 后发表回答