//
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2013 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
namespace IStation.Numerics.Random
{
///
/// This class implements extension methods for the System.Random class. The extension methods generate
/// pseudo-random distributed numbers for types other than double and int32.
///
public static class RandomExtensions
{
///
/// Fills an array with uniform random numbers greater than or equal to 0.0 and less than 1.0.
///
/// The random number generator.
/// The array to fill with random values.
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static void NextDoubles(this System.Random rnd, double[] values)
{
if (rnd is RandomSource rs)
{
rs.NextDoubles(values);
return;
}
for (var i = 0; i < values.Length; i++)
{
values[i] = rnd.NextDouble();
}
}
///
/// Returns an array of uniform random numbers greater than or equal to 0.0 and less than 1.0.
///
/// The random number generator.
/// The size of the array to fill.
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static double[] NextDoubles(this System.Random rnd, int count)
{
var values = new double[count];
NextDoubles(rnd, values);
return values;
}
///
/// Returns an infinite sequence of uniform random numbers greater than or equal to 0.0 and less than 1.0.
///
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static IEnumerable NextDoubleSequence(this System.Random rnd)
{
if (rnd is RandomSource rs)
{
return rs.NextDoubleSequence();
}
return NextDoubleSequenceEnumerable(rnd);
}
static IEnumerable NextDoubleSequenceEnumerable(System.Random rnd)
{
while (true)
{
yield return rnd.NextDouble();
}
}
///
/// Returns an array of uniform random bytes.
///
/// The random number generator.
/// The size of the array to fill.
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static byte[] NextBytes(this System.Random rnd, int count)
{
var values = new byte[count];
rnd.NextBytes(values);
return values;
}
///
/// Fills an array with uniform random 32-bit signed integers greater than or equal to zero and less than .
///
/// The random number generator.
/// The array to fill with random values.
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static void NextInt32s(this System.Random rnd, int[] values)
{
if (rnd is RandomSource rs)
{
rs.NextInt32s(values);
return;
}
for (var i = 0; i < values.Length; i++)
{
values[i] = rnd.Next();
}
}
///
/// Fills an array with uniform random 32-bit signed integers within the specified range.
///
/// The random number generator.
/// The array to fill with random values.
/// Lower bound, inclusive.
/// Upper bound, exclusive.
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static void NextInt32s(this System.Random rnd, int[] values, int minInclusive, int maxExclusive)
{
if (rnd is RandomSource rs)
{
rs.NextInt32s(values, minInclusive, maxExclusive);
return;
}
for (var i = 0; i < values.Length; i++)
{
values[i] = rnd.Next(minInclusive, maxExclusive);
}
}
///
/// Returns an infinite sequence of uniform random numbers greater than or equal to 0.0 and less than 1.0.
///
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static IEnumerable NextInt32Sequence(this System.Random rnd, int minInclusive, int maxExclusive)
{
if (rnd is RandomSource rs)
{
return rs.NextInt32Sequence(minInclusive, maxExclusive);
}
return NextInt32SequenceEnumerable(rnd, minInclusive, maxExclusive);
}
static IEnumerable NextInt32SequenceEnumerable(System.Random rnd, int minInclusive, int maxExclusive)
{
while (true)
{
yield return rnd.Next(minInclusive, maxExclusive);
}
}
///
/// Returns a nonnegative random number less than .
///
/// The random number generator.
///
/// A 64-bit signed integer greater than or equal to 0, and less than ; that is,
/// the range of return values includes 0 but not .
///
///
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static long NextInt64(this System.Random rnd)
{
var buffer = new byte[8];
rnd.NextBytes(buffer);
var candidate = BitConverter.ToInt64(buffer, 0);
// wrap negative numbers around, mapping every negative number to a distinct nonnegative number
// MinValue -> 0, -1 -> MaxValue
candidate &= long.MaxValue;
// skip candidate if it is MaxValue. Recursive since rare.
return (candidate == long.MaxValue) ? rnd.NextInt64() : candidate;
}
///
/// Returns a random number of the full Int32 range.
///
/// The random number generator.
///
/// A 32-bit signed integer of the full range, including 0, negative numbers,
/// and .
///
///
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static int NextFullRangeInt32(this System.Random rnd)
{
var buffer = new byte[4];
rnd.NextBytes(buffer);
return BitConverter.ToInt32(buffer, 0);
}
///
/// Returns a random number of the full Int64 range.
///
/// The random number generator.
///
/// A 64-bit signed integer of the full range, including 0, negative numbers,
/// and .
///
///
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static long NextFullRangeInt64(this System.Random rnd)
{
var buffer = new byte[8];
rnd.NextBytes(buffer);
return BitConverter.ToInt64(buffer, 0);
}
///
/// Returns a nonnegative decimal floating point random number less than 1.0.
///
/// The random number generator.
///
/// A decimal floating point number greater than or equal to 0.0, and less than 1.0; that is,
/// the range of return values includes 0.0 but not 1.0.
///
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static decimal NextDecimal(this System.Random rnd)
{
decimal candidate;
// 50.049 % chance that the number is below 1.0. Try until we have one.
// Guarantees that any decimal in the interval can
// indeed be reached, with uniform probability.
do
{
candidate = new decimal(
rnd.NextFullRangeInt32(),
rnd.NextFullRangeInt32(),
rnd.NextFullRangeInt32(),
false,
28);
}
while (candidate >= 1.0m);
return candidate;
}
///
/// Returns a random boolean.
///
/// The random number generator.
///
/// This extension is thread-safe if and only if called on an random number
/// generator provided by Math.NET Numerics or derived from the RandomSource class.
///
public static bool NextBoolean(this System.Random rnd)
{
return rnd.NextDouble() >= 0.5;
}
}
}