// // 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; } } }