Non-Uniform Random Numbers in C# QuickStart Sample
Illustrates how to generate random numbers from a non-uniform distribution in C#.
This sample is also available in: Visual Basic, F#, IronPython.
Overview
This QuickStart sample demonstrates how to generate random numbers from non-uniform probability distributions using Numerics.NET.
The sample specifically illustrates the relationship between exponential and Poisson distributions in modeling events over time. It uses an exponential distribution to generate times between events, and then compares the resulting frequency of events per time unit with the theoretical Poisson distribution.
The code shows how to:
- Create and configure specific probability distributions (Exponential and Poisson)
- Use the MersenneTwister random number generator
- Generate random samples from a probability distribution
- Collect and analyze statistical data from the generated samples
- Compare empirical results with theoretical expectations
This practical example helps understand both the mechanics of generating non-uniform random numbers and how different probability distributions relate to each other in modeling real-world phenomena.
The code
using System;
using Numerics.NET.Statistics.Distributions;
using Numerics.NET.Random;
// Illustrates generating non-uniform random numbers
// using the classes in the Numerics.NET.Statistics.Random
// namespace.
// The license is verified at runtime. We're using
// a 30 day trial key here. For more information, see
// https://numerics.net/trial-key
Numerics.NET.License.Verify("your-trial-key-here");
// Random number generators and the generation
// of uniform pseudo-random numbers are illustrated
// in the UniformRandomNumbers QuickStart Sample.
// In this sample, we will generate numbers from
// an exponential distribution, and compare summary
// results to what would be expected from
// the corresponding Poisson distribution.
double meanTimeBetweenEvents = 0.42;
// We will use the exponential distribution to generate the time
// between events. The number of events per unit time follows
// a Poisson distribution.
// The parameter of the exponential distribution is the time between events.
var exponential = new ExponentialDistribution(meanTimeBetweenEvents);
// The parameter of the Poisson distribution is the mean number of events
// per unit time, which is the reciprocal of the time between events:
var poisson = new PoissonDistribution(1 / meanTimeBetweenEvents);
// We use a MersenneTwister to generate the random numbers:
var random = new MersenneTwister();
// The totals array will track the number of events per time unit.
int[] totals = new int[15];
double currentTime = 0;
double endOfCurrentTimeUnit = 1;
int eventsInUnit = 0;
double totalTime = 0;
int count = 0;
while (currentTime < 100000)
{
double timeBetween = exponential.Sample(random);
totalTime += timeBetween; count++;
// Alternatively, we could have written
// timeBetween = random.NextDouble(exponential);
// which would give an identical result.
currentTime += timeBetween;
while (currentTime > endOfCurrentTimeUnit)
{
if (eventsInUnit >= totals.Length)
eventsInUnit = totals.Length-1;
totals[eventsInUnit]++;
eventsInUnit = 0;
endOfCurrentTimeUnit++;
}
eventsInUnit++;
}
Console.WriteLine($"{totalTime / count}");
// Now print the totals
Console.WriteLine("# Events Actual Expected");
for(int i = 0; i < totals.Length; i++)
{
int expected = (int)(100000 * poisson.Probability(i));
Console.WriteLine("{0,8} {1,8} {2,8}", i, totals[i], expected);
}
Console.Write("Press any key to exit.");
Console.ReadLine();