Random number seeding solution

Jibrohni

Freshman
Joined
Apr 15, 2010
Messages
28
Good day one and all,

I have a randomness headache...

I have a simulation that is trying to create upto 10,000 random decks of cards, one after the other, as quickly as possible.

The problem I seem to have is that each random Deck repeats 4 or 5 times before a new one is created. I think this may be because the random function works off the current tick or seed (I've tried using DateTime.Now.Millisecond as seed). It seems that it's managing 4 or 5 iterations before the tick or seed value actually changes. Is there anyway I can use a seed that will be quick enough to take effect before the next iteration?

I'm basically trying to build a poker odds calculator so it needs to be quick for the decision and extensive for the accuracy.

Any advice would be much appreciated.

Thanks!
 
The normal approach would be to use a single random number generator throughout an entire application. Other than for debugging purposes there are few situations where it makes sense to create more than one Random object (or call Randomize more than once).
 
Well I have a Deck class that gets instantiated at the beginning of each iteration. I then use the Shuffle() method to randomize each deck:

/// <summary>
/// method to shuffle the deck
/// </summary>
public void shuffle(int seed)
{
Random rnd = new Random(seed);
int sort1;
int sort2;
Card tmpcard = new Card();

for (int ctr = 0; ctr < 100; ctr++)
{
sort1 = (int)((rnd.NextDouble() * 52) + 1);
sort2 = (int)((rnd.NextDouble() * 52) + 1);

tmpcard = this.Cards[sort1];
this.Cards[sort1] = this.Cards[sort2];
this.Cards[sort2] = tmpcard;
}
this.next = 1; //reset pointer to first card
}

I'm not really sure what the problem is, but the output of random decks does the first two fine, but then after that each deck seems to be repeated in batches of 6 or 7.

Do you think it's because it's iterating through this many before there's a change in the seed value?
 
Ok guys, so I've managed to solve the problem by incorporating a high performance/high resolution timer. I used the class at the destination below:

http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx

I then took the .Duration value after starting the timer and used a Right function to take the 7 digits (the farthest right being the numbers changing most frequently). I then used these as my seed value.

HiPerfTimer ht = new HiPerfTimer();
ht.Start();
Random rnd = new Random(Convert.ToInt32(Right(ht.Duration.ToString(),7)));

I hope this helps others out.

Thanks again!
 
Last edited:
Why not just use a single random object?
Code:
public static class Program {
    // ... the usual ...
    
    Random randomGenerator = new Random();
    public Random RandomGenerator { get { return randomGenerator; }}
 
}

// Elsewhere...
// (two overloads... one to use a shared random generator
//   and one that allows a seed to be specified for debugging)
public void shuffle() 
{
    shuffle(-1); // Magic number
}
public void shuffle(int seed)
{
Random rnd;
if(seed == -1) // Magic number
    rnd = Program.RandomGenerator;
else
    rnd = new Random(seed);
int sort1;
int sort2;
Card tmpcard = new Card();

for (int ctr = 0; ctr < 100; ctr++)
{
sort1 = (int)((rnd.NextDouble() * 52) + 1);
sort2 = (int)((rnd.NextDouble() * 52) + 1);

tmpcard = this.Cards[sort1];
this.Cards[sort1] = this.Cards[sort2];
this.Cards[sort2] = tmpcard;
}
this.next = 1; //reset pointer to first card
}
With one Random object exposed through the Program class, it's easy for the entire program to use a single random number generator, as is generally considered good practice.
 
That's what I was doing before - but the change frequency of my seed value was lower than my random number iteration frequency - therefore it was repeating the same deck of cards 5 or 6 times before the seed value had a chance to change.

Using the high resolution timer meant that the seed value I was using was changing much more rapidly, beating the next iteration of my algorithm, and thus providing a completely new random deck.

Basically the tick rate was moving at a slower pace than my iterating algorithm.
 
That's what I was doing before - but the change frequency of my seed value was lower than my random number iteration frequency - therefore it was repeating the same deck of cards 5 or 6 times before the seed value had a chance to change.

Using the high resolution timer meant that the seed value I was using was changing much more rapidly, beating the next iteration of my algorithm, and thus providing a completely new random deck.

Basically the tick rate was moving at a slower pace than my iterating algorithm.

well at least I think that was the problem - it certainly got the result I was after.
 
Code:
public void shuffle(int seed)
{
Random rnd = new Random(seed);
This code creates a new random object every time the function is called. The instantiation occurs in the function, therefore you create an instance each time the function is invoked. If it is called in succession too quickly you will get the same seed on those successive calls. That was the original problem.
Code:
public static class Program {
    // ... the usual ...
    
    Random randomGenerator = new Random();
    public Random RandomGenerator { get { return randomGenerator; }}
 
}
This creates a single random object. It is a static declaration, so you get one instance shared everywhere. The point is that you seed it only once, ever. If you only seed it once, you don't have to worry about seeding it too frequently.
Code:
HiPerfTimer ht = new HiPerfTimer();
ht.Start();
Random rnd = new Random(Convert.ToInt32(Right(ht.Duration.ToString(),7)));
This is like putting a turbo in your car to compensate for the fact that the hand brake is engaged. Just dis-engage the hand brake.

And what happens when your program is run on a machine that doesn't have a high resolution timer?
 
Ha-ha you swine - you've managed to take that tiny bit of glory away from me!!

I hate to say it, but thanks again. I'll have a muck around and see for myself.

*whimpering*

back soon...
 
Ha-ha you swine - you've managed to take that tiny bit of glory away from me!!

I hate to say it, but thanks again. I'll have a muck around and see for myself.

*whimpering*

back soon...

*still whimpering*

...at least on the plus side I now know that you can leave the handbrake on all the time if you've got a turbo installed...

Thanks again!!
 
Back
Top