C# RandomProvider Class
A C# class to provide random numbers for a variety of data types and statistical distributions
By
Steve on
Tuesday, January 09, 2007
Updated
Friday, April 22, 2016
Viewed
37,560 times. (
1 times today.)
Summary
The .NET Framework provides System.Random for generating random numbers which provides uniform random numbers of type System.Double in the range [0,1). However, in practice one almost always needs random numbers in a different range and often of a different type. I created the RandomProvider class as a more useful wrapper for the Random class and I use it all the time.
Example: How to use the RandomProvider Class
public static void TestRandomProvider()
{
// Random double [0,1)
Console.WriteLine("Random Double [0,1) = " + RandomProvider.Next());
// Random Int64 [50,100)
long ran = RandomProvider.Next(50,100);
Console.WriteLine("Random Int64 [50,100) = " + ran);
// Random Boolean
Console.WriteLine("Random Boolean = " + RandomProvider.NextBoolean());
// Random DateTime [1/1/1998, 6/1/1998)
DateTime minDT = DateTime.Parse("1/1/1998");
DateTime maxDT = DateTime.Parse("6/1/1998");
DateTime ranDT = RandomProvider.Next(minDT, maxDT);
Console.WriteLine("Random DateTime [1/1/1998, 6/1/1998) = " + ranDT);
// Random TimeSpan [3 hours, 7 hours)
TimeSpan minTs = new TimeSpan(3, 0, 0);
TimeSpan maxTs = new TimeSpan(7, 0, 0);
TimeSpan ranTs = RandomProvider.Next(minTs, maxTs);
Console.WriteLine("Random TimeSpan [3 hrs, 7 hrs) = " + ranTs);
// Random Normal Deviate
Console.WriteLine("Normal deviate = "
+ RandomProvider.NextNormal());
// Random Exponential Deviate
Console.WriteLine("Exponential deviate = "
+ RandomProvider.NextExponential());
}
If you run the previous method you'll get something similar to the following output:
Example: Output
Random Double [0,1) = 0.147433493820687
Random Int64 [50,100) = 69
Random Boolean = False
Random DateTime [1/1/1998, 6/1/1998) = 2/4/1998 4:09:50 AM
Random TimeSpan [3 hrs, 7 hrs) = 03:58:55.0844951
Normal deviate = 0.277308108809515
Exponential deviate = 1.37058190966813
The C# RandomProvider Class:
using System;
namespace Cambia.CoreLib
{
/// <summary>
/// RandomProvider. Provides random numbers of all data types
/// in specified ranges. It also contains a couple of methods
/// from Normally (Gaussian) distributed random numbers and
/// Exponentially distributed random numbers.
/// </summary>
public class RandomProvider
{
private static Random m_RNG1;
private static double m_StoredUniformDeviate;
private static bool m_StoredUniformDeviateIsGood = false;
#region -- Construction/Initialization --
static RandomProvider()
{
Reset();
}
public static void Reset()
{
m_RNG1 = new Random(Environment.TickCount);
}
#endregion
#region -- Uniform Deviates --
/// <summary>
/// Returns double in the range [0, 1)
/// </summary>
public static double Next()
{
return m_RNG1.NextDouble();
}
/// <summary>
/// Returns true or false randomly.
/// </summary>
public static bool NextBoolean()
{
if (m_RNG1.Next(0,2) == 0)
return false;
else
return true;
}
/// <summary>
/// Returns double in the range [0, 1)
/// </summary>
public static double NextDouble()
{
double rn = m_RNG1.NextDouble();
return rn;
}
/// <summary>
/// Returns Int16 in the range [min, max)
/// </summary>
public static Int16 Next(Int16 min, Int16 max)
{
if (max <= min)
{
string message = "Max must be greater than min.";
throw new ArgumentException(message);
}
double rn = (max*1.0 - min*1.0)*m_RNG1.NextDouble() + min*1.0;
return Convert.ToInt16(rn);
}
/// <summary>
/// Returns Int32 in the range [min, max)
/// </summary>
public static int Next(int min, int max)
{
return m_RNG1.Next(min, max);
}
/// <summary>
/// Returns Int64 in the range [min, max)
/// </summary>
public static Int64 Next(Int64 min, Int64 max)
{
if (max <= min)
{
string message = "Max must be greater than min.";
throw new ArgumentException(message);
}
double rn = (max*1.0 - min*1.0)*m_RNG1.NextDouble() + min*1.0;
return Convert.ToInt64(rn);
}
/// <summary>
/// Returns float (Single) in the range [min, max)
/// </summary>
public static Single Next(Single min, Single max)
{
if (max <= min)
{
string message = "Max must be greater than min.";
throw new ArgumentException(message);
}
double rn = (max*1.0 - min*1.0)*m_RNG1.NextDouble() + min*1.0;
return Convert.ToSingle(rn);
}
/// <summary>
/// Returns double in the range [min, max)
/// </summary>
public static double Next(double min, double max)
{
if (max <= min)
{
string message = "Max must be greater than min.";
throw new ArgumentException(message);
}
double rn = (max - min)*m_RNG1.NextDouble() + min;
return rn;
}
/// <summary>
/// Returns DateTime in the range [min, max)
/// </summary>
public static DateTime Next(DateTime min, DateTime max)
{
if (max <= min)
{
string message = "Max must be greater than min.";
throw new ArgumentException(message);
}
long minTicks = min.Ticks;
long maxTicks = max.Ticks;
double rn = (Convert.ToDouble(maxTicks)
- Convert.ToDouble(minTicks))*m_RNG1.NextDouble()
+ Convert.ToDouble(minTicks);
return new DateTime(Convert.ToInt64(rn));
}
/// <summary>
/// Returns TimeSpan in the range [min, max)
/// </summary>
public static TimeSpan Next(TimeSpan min, TimeSpan max)
{
if (max <= min)
{
string message = "Max must be greater than min.";
throw new ArgumentException(message);
}
long minTicks = min.Ticks;
long maxTicks = max.Ticks;
double rn = (Convert.ToDouble(maxTicks)
- Convert.ToDouble(minTicks))*m_RNG1.NextDouble()
+ Convert.ToDouble(minTicks);
return new TimeSpan(Convert.ToInt64(rn));
}
/// <summary>
/// Returns double in the range [min, max)
/// </summary>
public static double NextUniform()
{
return Next();
}
/// <summary>
/// Returns a uniformly random integer representing one of the values
/// in the enum.
/// </summary>
public static int NextEnum(Type enumType)
{
int[] values = (int[])Enum.GetValues(enumType);
int randomIndex = Next(0, values.Length);
return values[randomIndex];
}
#endregion
#region -- Exponential Deviates --
/// <summary>
/// Returns an exponentially distributed, positive, random deviate
/// of unit mean.
/// </summary>
public static double NextExponential()
{
double dum = 0.0;
while (dum == 0.0)
dum=NextUniform();
return -1.0*System.Math.Log(dum, System.Math.E);
}
#endregion
#region -- Normal Deviates --
/// <summary>
/// Returns a normally distributed deviate with zero mean and unit
/// variance.
/// </summary>
public static double NextNormal()
{
// based on algorithm from Numerical Recipes
if (m_StoredUniformDeviateIsGood)
{
m_StoredUniformDeviateIsGood = false;
return m_StoredUniformDeviate;
}
else
{
double rsq = 0.0;
double v1 = 0.0, v2 = 0.0, fac = 0.0;
while (rsq >=1.0 || rsq == 0.0)
{
v1 = 2.0*Next() - 1.0;
v2 = 2.0*Next() - 1.0;
rsq = v1*v1 + v2*v2;
}
fac = System.Math.Sqrt(-2.0
*System.Math.Log(rsq, System.Math.E)/rsq);
m_StoredUniformDeviate = v1*fac;
m_StoredUniformDeviateIsGood = true;
return v2*fac;
}
}
#endregion
}
}