How to Generate Truly (Not Pseudo) Random Numbers with C#

How can I generate truly (not pseudo) random numbers with C#?

The answer here has two main sides to it. There are some quite important subtleties to which you should pay due attention...

The Easy Way (for simplicity & practicality)

The RNGCryptoServiceProvider, which is part of the Crypto API in the BCL, should do the job for you. It's still technically a pseudo-random number generated, but the quality of "randomness" is much higher - suitable for cryptographic purposes, as the name might suggest.

There are other crypographic APIs with high quality pseudo random generaters available too. Algorithms such as the Mersenne twister are quite popular.

Comparing this to the Random class in the BCL, it is significantly better. If you plot the numbers generated by Random on a graph, for example, you should be able to recognise patterns, which is a strong sign of weakness. This is largely due to the fact that the algorithm simply uses a seeded lookup table of fixed size.

The Hard Way (for high quality theoretical randomness)

To generate truly random numbers, you need to make use of some natural phenomenon, such as nuclear decay, microscopic temperature fluctuations (CPU temperature is a comparatively conveient source), to name a few. This however is much more difficult and requires additional hardware, of course. I suspect the practical solution (RNGCryptoServiceProvider or such) should do the job perfectly well for you.

Now, note that if you really do require truly random numbers, you could use a service such as Random.org, which generates numbers with very high randomness/entropy (based on atmospheric noise). Data is freely available for download. This may nonetheless be unnecessarily complicated for your situation, although it certainly gives you data suitable for scientific study and whatnot.

The choice is yours in the end, but at least you should now be able to make an informative decision, being aware of the various types and levels of RNGs.

Creating a true random

DateTime.Now.Ticks only has a resolution of approximately 16ms, so if you create a Random with that overload multiple times within a 16ms "slot" they will all be seeded with the same value and therefore you will get the same sequence.

Initialize your Random outside your loop so that a single Random sequence is produced, rather than creating it each time within the loop which could result in Randoms being seeded with the same value and so produce the same sequence.

Update

My previous point that the default constructor initialized Random with CPU ticks was incorrect, the default constructor actually uses Environment.TickCount which is:

A 32-bit signed integer containing the amount of time in milliseconds that has passed since the last time the computer was started.

Which still has a low resolution. If you make multiple instances of Random in quick succession, they can easily be created within the same time slot and therefore have the same seed value, and create the same sequence. Create a single instance of Random and use that.

Update

Further to your comments, if you wish to generate a random sequence across multiple threads, please see the following Jon Skeet article which discusses a thread-safe wrapper:

https://codeblog.jonskeet.uk/2009/11/04/revisiting-randomness

Random Binary Generator (not pseudo)

function randomInt(max)
// produces integer with uniform distribution between [0,max)
# this should be in your standard library
# though perhaps not by this name; and you may need to
# initialize and maybe randomly seed your RNG beforehand

myRandomBinaryNumber = randomInt(2^10) // then cast it if required

edit: this answer added before "(not pseudo)" added to title

edit: I recommend the methods listed in other answers, depending on one's needs (pseudorandom, cryptographically pseudorandom, truly random, etc.)

Is the C# random number generator guaranteed to be stable?

No, the result from the same seed can vary across versions of the framework, and it's in the documentation here:

The implementation of the random number generator in the Random class isn't guaranteed to remain the same across major versions of the .NET Framework. As a result, you shouldn't assume that the same seed will result in the same pseudo-random sequence in different versions of the .NET Framework.

That documentation also contains variations of this advice in other sections, e.g. in Retrieve the same sequence of random values:

The following example uses 100100 as an arbitrary seed value to instantiate the Random object, displays 20 random floating-point values, and persists the seed value. It then restores the seed value, instantiates a new random number generator, and displays the same 20 random floating-point values. Note that the example may produce different sequences of random numbers if run on different versions of the .NET Framework.

And:

However, note that Random objects in processes running under different versions of the .NET Framework may return different series of random numbers even if they're instantiated with identical seed values.

Randomly generated values are not really random

Random numbers use a seedvalue to start the sequence. If you give nothing, it takes to current datetime.now value. if you supply the same value (like 3842) you will get the same sequence of random values guaranteed. Your series seemed to be very closely related so you see the same values. All this can be read in the documentation on msdn, see Instantiate pseudo random :

Instantiating the random number generator

You instantiate the random number generator by providing a seed value (a starting value for the pseudo-random number generation algorithm) to a Random class constructor. You can supply the seed value either explicitly or implicitly:

The Random(Int32) constructor uses an explicit seed value that you supply.

The Random() constructor uses the system clock to provide a seed value. This is the most common way of instantiating the random number generator.

If the same seed is used for separate Random objects, they will generate the same series of random numbers. This can be useful for creating a test suite that processes random values, or for replaying games that derive their data from random numbers. However, note that Random objects in processes running under different versions of the .NET Framework may return different series of random numbers even if they're instantiated with identical seed values.

Source: https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx#Instantiate

You find more information and even methods to "better" cryptographical random methods linked above the source I cited.

Algorithm to generate a random number? Don't use System.Random

True random numbers can only be generated "outside" a computer, using radioactivity counts and such. Some VIA processors have hardware to do so.

Volume two of The Art of Computer Programming by Don Knuth spends a lot of time discussing exhaustively various pseudo-random number implementations from a mathematical background. Recommended reading.

pseudo random number generation

Create a list with the numbers you want to have, and then randomly select an element from this list and remove it.

Repeat this until your list is empty, and start over again.

This way you will get each number once in n tries, but their order will be random.

Pseudo Random Number Generator C#

What you want is a randomly "ordered" list, not a randomly "generated" list. This is usually called "Shuffling".

Here's some sample code (not good code by any means, but I made it as close as yours as a sample) to achieve what you want:

static void Shuffle(int[] list)
{
var rnd = new Random();
int n = list.Count();
while (n > 1)
{
n--;
int k = rnd.Next(n + 1);
int value = list[k];
list[k] = list[n];
list[n] = value;
}
}

static void Main(string[] args)
{
int min = 1;
int max = 10;
int [] numbers = new int[max-min];

for (int i = min; i < max; i++)
numbers[i-min] = i;

Shuffle(numbers);

string display = "";
for (int i = min; i < max; i++)
display += " " + numbers[i-min];
Console.Write(display);
}

The result should be something like:

4 9 2 1 3 7 5 8 6

Should work for any min and max values (generating as much numbers as there are in-between)

How do I generate a random integer in C#?

The Random class is used to create random numbers. (Pseudo-random that is of course.).

Example:

Random rnd = new Random();
int month = rnd.Next(1, 13); // creates a number between 1 and 12
int dice = rnd.Next(1, 7); // creates a number between 1 and 6
int card = rnd.Next(52); // creates a number between 0 and 51

If you are going to create more than one random number, you should keep the Random instance and reuse it. If you create new instances too close in time, they will produce the same series of random numbers as the random generator is seeded from the system clock.



Related Topics



Leave a reply



Submit