Last updated on June 29, 2019
I was digging around in an old program I wrote and saw a method I wrote for random number generation. It reminded me that some programmers may not realize the problem with the normal random number code in .Net – and how the numbers are actually predictable.
If you use the System.Random class, and create new instance of it with every use, you’ll get the same numbers, in the same order.
To see the problem, run a program that uses a System.Random object to generate 10 random numbers. Write those numbers down, and then stop the program. Now, run the program again. You’ll see that it gives you the same 10 numbers, in the exact same order.
This happens because the random number generator initializes itself with a seed value. But it’s the same seed value each time you run the program. So, you get the same results. This is often called “pseudo-random” numbers.
A better method is to use the random number generator in the cryptography library of the .Net framework. It may not be a 100%, true random number (if you want to get into high-level mathematics), but it’s good enough for almost anything most of us will ever need.
Here’s the code I used to create a random number between two numbers (inclusive):
RandomNumber.cs class
using System; using System.Security.Cryptography; namespace FDL.Library.Numeric { public static class RandomNumber { private static readonly RNGCryptoServiceProvider _generator = new RNGCryptoServiceProvider(); public static int Between(int minimumValue, int maximumValue) { byte[] randomNumber = new byte[1]; _generator.GetBytes(randomNumber); double asciiValueOfRandomCharacter = Convert.ToDouble(randomNumber[0]); // We are using Math.Max, and substracting 0.00000000001, // to ensure "multiplier" will always be between 0.0 and .99999999999 // Otherwise, it's possible for it to be "1", which causes problems in our rounding. double multiplier = Math.Max(0, (asciiValueOfRandomCharacter / 255d) - 0.00000000001d); // We need to add one to the range, to allow for the rounding done with Math.Floor int range = maximumValue - minimumValue + 1; double randomValueInRange = Math.Floor(multiplier * range); return (int)(minimumValue + randomValueInRange); } } }
The reason this method has minimumValue and maximumValue parameters was because I needed to be able to generate a random number between 5 and 10 (for example).
So, if you’re creating a .Net game, or any other .Net program where you want to have something randomized, use a method like this to give you better random results.
EDIT: 28 Apr 2014
I moved the generator variable to a static class-level variable, so we don’t keep creating new instances of this object – or need to worry about disposing them.
thank you, really helping me 🙂
You’re welcome
Hi,
Thanks for this process. I need to use a RNG to access existing array elements so my question is this: Is “0” (zero) a valid low range value?
I wrote a little C# app to test this with zero and found out for myself that it does indeed work. Thanks for the code, it will make my language learning flashcard selection a little less predictable! Good work.
Hi,
I’m sorry I couldn’t answer. I didn’t have Internet until last night. But you figured out the best way to see if it works. 🙂 Good luck with your language learning program!
Thanks, this is a simpler approach than what I was using and so far it is working well for me. Thanks for taking the time to post your code.
You’re welcome
Nice. Also, if you know that you need to generate say 10,000 random number in advance (so they are available instantly), it is very easy to change the above code to return an array of 10,000 or whatever random numbers all at once. This routine returns ‘amount’ of random numbers. It is similar except I changed the maximumValue to be exclusive… so (zero to maximumValue – 1):
That would be nice to run, to verify the random number distribution is really random. That’s always a good idea, when using a random number generation function. 🙂
The method seems to generate biased numbers.
If I try to generate numbers between 1 and 10, the chance of getting 5 is 9.77% and the chance of getting 6 is 10.17% (10 million samples)
That is interesting. I tried it and saw the same results as you. However, when I first wrote this, I know I did a similar test and saw more-balanced results. I’m going to try some things with it this weekend, to see if I can track down what is happening.
Could you tell me if you see anything wrong with this code? On tens of millions of runs I can see that numbers distribute not absolutely evenly, but deviations are within 1%. Do we expect any better from software pseudo-random generator?
From what I’ve seen, it is very unlikely that the numbers will distribute exactly evenly. I’m not an expert at the mathematics behind this, but you might be able to investigate deeper with some of the information here http://www.drdobbs.com/testing-random-number-generators/184403185 and here https://www.random.org/analysis/.