Skip to content

Instantly share code, notes, and snippets.

@michel-pi
Created April 1, 2019 07:20
Show Gist options
  • Save michel-pi/3853ad62dd02c99affc0b7439b7a6da0 to your computer and use it in GitHub Desktop.
Save michel-pi/3853ad62dd02c99affc0b7439b7a6da0 to your computer and use it in GitHub Desktop.
A static and thread safe pseudo-random number generator
using System;
using System.Threading;
namespace System
{
/// <summary>
/// Represents a static and thread safe pseudo-random number generator, which is a device that produces a sequence of numbers that meet certain statistical requirements for randomness.
/// </summary>
public static class StaticRandom
{
[ThreadStatic] private static int seed;
[ThreadStatic] private static Random random;
/// <summary>
/// Gets the value of the seed which was used when the pseudo-random number generator was initialized.
/// </summary>
public static int Seed
{
get
{
return seed;
}
}
/// <summary>
/// Returns a non-negative random integer.
/// </summary>
/// <returns>A 32-bit signed integer that is greater than or equal to 0 and less than <see cref="F:System.Int32.MaxValue" />.</returns>
public static int Next()
{
if (random == null) random = GetRandomNumberGenerator();
return random.Next();
}
/// <summary>
/// Returns a non-negative random integer that is less than the specified maximum.
/// </summary>
/// <param name="maxValue">The exclusive upper bound of the random number to be generated. <paramref name="maxValue" /> must be greater than or equal to 0.</param>
/// <returns>A 32-bit signed integer that is greater than or equal to 0, and less than <paramref name="maxValue" />; that is, the range of return values ordinarily includes 0 but not <paramref name="maxValue" />. However, if <paramref name="maxValue" /> equals 0, <paramref name="maxValue" /> is returned.</returns>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maxValue" /> is less than 0. </exception>
public static int Next(int maxValue)
{
if (random == null) random = GetRandomNumberGenerator();
return random.Next(maxValue);
}
/// <summary>
/// Returns a random integer that is within a specified range.
/// </summary>
/// <param name="minValue">The inclusive lower bound of the random number returned.</param>
/// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue" /> must be greater than or equal to <paramref name="minValue" />.</param>
/// <returns>A 32-bit signed integer greater than or equal to <paramref name="minValue" /> and less than <paramref name="maxValue" />; that is, the range of return values includes <paramref name="minValue" /> but not <paramref name="maxValue" />. If <paramref name="minValue" /> equals <paramref name="maxValue" />, <paramref name="minValue" /> is returned.</returns>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minValue" /> is greater than <paramref name="maxValue" />. </exception>
public static int Next(int minValue, int maxValue)
{
if (random == null) random = GetRandomNumberGenerator();
return random.Next(minValue, maxValue);
}
/// <summary>
/// Fills the elements of a specified array of bytes with random numbers.
/// </summary>
/// <param name="buffer">An array of bytes to contain random numbers.</param>
/// /// <exception cref="T:System.ArgumentNullException"><paramref name="buffer" /> is <see langword="null" />. </exception>
public static void NextBytes(byte[] buffer)
{
if (random == null) random = GetRandomNumberGenerator();
random.NextBytes(buffer);
}
/// <summary>
/// Returns a random boolean.
/// </summary>
/// <returns>A boolean value.</returns>
public static bool NextBool()
{
return NextDouble() >= 0.5;
}
/// <summary>
/// Returns a random floating-point number that is greater than or equal to 0.0, and less than 1.0.
/// </summary>
/// <returns>A double-precision floating point number that is greater than or equal to 0.0, and less than 1.0.</returns>
public static double NextDouble()
{
if (random == null) random = GetRandomNumberGenerator();
return random.NextDouble();
}
/// <summary>
/// Returns a random floating-point number that is greater than or equal to 0.0, and less than <paramref name="maxValue" />.
/// </summary>
/// <param name="maxValue">The exclusive upper bound of the random number returned.</param>
/// <returns>A double-precision floating point number that is greater than or equal to 0, and less than <paramref name="maxValue" />; that is, the range of return values ordinarily includes 0 but not <paramref name="maxValue" />.</returns>
public static double NextDouble(double maxValue)
{
if (double.IsInfinity(maxValue)
|| double.IsNaN(maxValue)
|| maxValue < 1.0d) throw new ArgumentOutOfRangeException(nameof(maxValue));
return NextDouble() * maxValue;
}
/// <summary>
/// Returns a random floating-point number that is within a specified range.
/// </summary>
/// <param name="minValue">The inclusive lower bound of the random number returned.</param>
/// <param name="maxValue">The exclusive upper bound of the random number returned.</param>
/// <returns>A double-precision floating point number that is greater than or equal to <paramref name="minValue" />, and less than <paramref name="maxValue" />; that is, the range of return values ordinarily includes 0 but not <paramref name="maxValue" />.</returns>
public static double NextDouble(double minValue, double maxValue)
{
if (double.IsInfinity(minValue)
|| double.IsNaN(minValue)
|| minValue >= maxValue) throw new ArgumentOutOfRangeException(nameof(maxValue));
if (double.IsInfinity(maxValue)
|| double.IsNaN(maxValue)
|| maxValue < 1.0d) throw new ArgumentOutOfRangeException(nameof(maxValue));
return minValue + NextDouble() * (maxValue - minValue);
}
private static Random GetRandomNumberGenerator()
{
seed = Environment.TickCount ^ ((Thread.CurrentThread.ManagedThreadId + 1) * 23);
return new Random(seed);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment