I am using Random to generate a sequence of random number. I am constructing the random object just once and then inside the loop generating the random values (300 of them). The problem is that once I get all the values and do a sort on them I realize that some of them are equal and/or sequential: I am generating numbers from 0 to 50000.
This is my script:
Random rnd = new Random();
for (int n=0; n < 300; n++)
{
int RndNumber = rnd.Next(0, 50000);
System.Threading.Thread.Sleep(3);
}
Can someone have a clue on why this is happening, and how can I improve this to make it more random?
Since a truly random number needs to be completely unpredictable, it can never depend on deterministic input. If you have an algorithm which takes pre-determined input and uses it to produce a pseudo-random number, you can duplicate this process at will just as long as you know the input and algorithm.
And for most folks, the built-in random generator for Excel works fine for their needs. However, Excel uses what is called a pseudorandom number generator, in this case, the Mersenne Twister algorithm. What that means is that, technically speaking, the numbers that Excel's RAND functions generate aren't truly random.
So this is the birthday paradox*. When you draw 300 numbers from 50000 the approximate probability that at least two of them are equal is
p(300) = 1 - exp(-300 * 300 / (2 * 50000))
= 0.59
(I could work out the exact probability but I'm lazy!.)
So, chances are more likely than not that you'll have a collision. Sequential is even more likely (now you don't need a collision, you just need n - 1
and n
or n
and n + 1
to be hit for some n
).
Random is fickle.
*: In case you're not familiar with it, it says that if you have twenty-three people in a room, it is more likely than not that at least two people in the room share the same birthday.
!: Okay, I worked it out. It's 0.5953830515549951746819986449....
Research:
If you use the constructor without parameters new Random()
the seed is depending on the current servertime.
Random(): "Initializes a new instance of the Random class, using a time-dependent" http://msdn.microsoft.com/en-us/library/system.random.aspx
So, if I try it like this:
for(int i = 0; i < 1000; i++)
{
Random ran = new Random();
Console.WriteLine(ran.Next(50001));
}
I only get 3 different numbers about 300 times within a thousand calls! Not that random...
Setting the seed in the constructor new Random(0)
returns a fix serie of numbers.
e.g. new Random(0).Next(50)
always! returns 36. Try it yourself, if you don't trust me;
What we need for "real" random numbers is a changing seed, that's independent of time.
I'm using Hashcode of changing values:
e.g. Guid.NewGuid().GetHashCode()
or DateTime.Now.GetHashCode()
Result:
Random ran = new Random(Guid.NewGuid().GetHashCode());
for(int i = 0; i < 1000; i++)
{
Console.WriteLine(ran.Next(50001));
}
or (for better performance):
for(int i = 0; i < 1000; i++)
{
int val = Guid.NewGuid().GetHashCode() % 50001;
val = val > 0 ? val : -val;
Console.WriteLine(val);
}
PS: The maximum of the Next(max)-method is always max - 1;
-> ran.Next(11) can return 0,1,2,...,8,9,10. Not 11!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With