To really test out random number generation...
Open a console project and call the program.cs constructor to generate 30 randoms of 1,4 and console writeline (i) after every loop.
To really test out a random generator, you would want to be generating far more than 30 values. The first problem is that people are really bad at recognising random signals. People are biased towards interpreting repetition as non-random.
One key aspect of psuedo-random number generation is that all outputs should be reasonably likely, over a large number of invocations. That is, the generator should avoid bias in its output.
Here is a quick test program I threw together to demonstrate how you might test for such bias, using the default range function, and two simple implementations of such a function:
using System;
public class Test {
public static void Main(string [] args) {
if(args.Length != 2) {
Console.WriteLine("Usage: <number of digits> <number of iterations>");
return;
}
int n = int.Parse(args[0]);
int iterations = int.Parse(args[1]);
Random random = new Random();
int [] frequency;
Console.WriteLine("-------------------------------");
Console.WriteLine("Default random range generation");
Console.WriteLine("-------------------------------");
frequency = new int[n];
for(int i = 0 ; i < iterations ; ++i) {
int index = random.Next(0, n);
frequency[index]++;
}
for(int i = 0 ; i < n ; ++i) {
Console.WriteLine("Frequency of number " + i + ": " + (frequency * 100.0f / iterations) + "%");
}
Console.WriteLine("-------------------------------");
Console.WriteLine("Explicit use of low order bits");
Console.WriteLine("-------------------------------");
frequency = new int[n];
for(int i = 0 ; i < iterations ; ++i) {
int index = random.Next() % n;
frequency[index]++;
}
for(int i = 0 ; i < n ; ++i) {
Console.WriteLine("Frequency of number " + i + ": " + (frequency * 100.0f / iterations) + "%");
}
Console.WriteLine("-------------------------------");
Console.WriteLine("Casting next double to int");
Console.WriteLine("-------------------------------");
frequency = new int[n];
for(int i = 0 ; i < iterations ; ++i) {
int index = (int)(random.NextDouble() * n);
frequency[index]++;
}
for(int i = 0 ; i < n ; ++i) {
Console.WriteLine("Frequency of number " + i + ": " + (frequency * 100.0f / iterations) + "%");
}
}
}
Here is the output on my Linux machine (i.e. using mono, not Microsoft's implementation, YMMV):
user@host:~$ c# test.cs && ./test.exe 10 10000000
-------------------------------
Default random range generation
-------------------------------
Frequency of number 0: 9.99622%
Frequency of number 1: 9.99243%
Frequency of number 2: 10.00303%
Frequency of number 3: 10.02384%
Frequency of number 4: 9.98622%
Frequency of number 5: 9.9946%
Frequency of number 6: 10.00531%
Frequency of number 7: 10.00188%
Frequency of number 8: 10.00555%
Frequency of number 9: 9.99092%
-------------------------------
Explicit use of low order bits
-------------------------------
Frequency of number 0: 9.92869%
Frequency of number 1: 10.0747%
Frequency of number 2: 9.94714%
Frequency of number 3: 10.06481%
Frequency of number 4: 9.93947%
Frequency of number 5: 10.07618%
Frequency of number 6: 9.92547%
Frequency of number 7: 10.04247%
Frequency of number 8: 9.93499%
Frequency of number 9: 10.06608%
-------------------------------
Casting next double to int
-------------------------------
Frequency of number 0: 9.99552%
Frequency of number 1: 9.9953%
Frequency of number 2: 10.00841%
Frequency of number 3: 9.98883%
Frequency of number 4: 9.99405%
Frequency of number 5: 9.99853%
Frequency of number 6: 10.021%
Frequency of number 7: 10.01375%
Frequency of number 8: 9.99331%
Frequency of number 9: 9.9913%
Note that the middle block is far worse than the other two, it appears to be biased in favour of odd numbers. The middle block is, unfortunately, also the naive approach that many use when trying to generate random values in a given range.