// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2015 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; using MathNet.Numerics.Properties; namespace MathNet.Numerics.Random { /// /// Base class for random number generators. This class introduces a layer between /// and the Math.Net Numerics random number generators to provide thread safety. /// When used directly it use the System.Random as random number source. /// public abstract class RandomSource : System.Random { readonly bool _threadSafe; readonly object _lock = new object(); /// /// Initializes a new instance of the class using /// the value of to set whether /// the instance is thread safe or not. /// protected RandomSource() : base(RandomSeed.Robust()) { _threadSafe = Control.ThreadSafeRandomNumberGenerators; } /// /// Initializes a new instance of the class. /// /// if set to true , the class is thread safe. /// Thread safe instances are two and half times slower than non-thread /// safe classes. protected RandomSource(bool threadSafe) : base(RandomSeed.Robust()) { _threadSafe = threadSafe; } /// /// Fills an array with uniform random numbers greater than or equal to 0.0 and less than 1.0. /// /// The array to fill with random values. public void NextDoubles(double[] values) { if (_threadSafe) { lock (_lock) { for (var i = 0; i < values.Length; i++) { values[i] = DoSample(); } } } else { for (var i = 0; i < values.Length; i++) { values[i] = DoSample(); } } } /// /// Returns an array of uniform random numbers greater than or equal to 0.0 and less than 1.0. /// /// The size of the array to fill. public double[] NextDoubles(int count) { var values = new double[count]; NextDoubles(values); return values; } /// /// Returns an infinite sequence of uniform random numbers greater than or equal to 0.0 and less than 1.0. /// public IEnumerable NextDoubleSequence() { for (int i = 0; i < 64; i++) { yield return NextDouble(); } var buffer = new double[64]; while (true) { NextDoubles(buffer); for (int i = 0; i < buffer.Length; i++) { yield return buffer[i]; } } } /// /// Returns a random 32-bit signed integer greater than or equal to zero and less than . /// public sealed override int Next() { if (_threadSafe) { lock (_lock) { return DoSampleInteger(); } } return DoSampleInteger(); } /// /// Returns a random number less then a specified maximum. /// /// The exclusive upper bound of the random number returned. /// A 32-bit signed integer less than . /// is negative. public sealed override int Next(int maxExclusive) { if (maxExclusive <= 0) { throw new ArgumentException(Resources.ArgumentMustBePositive); } if (maxExclusive == int.MaxValue) { return Next(); } if (_threadSafe) { lock (_lock) { return DoSampleInteger(0, maxExclusive); } } return DoSampleInteger(0, maxExclusive); } /// /// Returns a random number within a specified range. /// /// The inclusive lower bound of the random number returned. /// The exclusive upper bound of the random number returned. must be greater than or equal to . /// /// A 32-bit signed integer greater than or equal to and less than ; that is, the range of return values includes but not . If equals , is returned. /// /// is greater than . public sealed override int Next(int minInclusive, int maxExclusive) { if (minInclusive > maxExclusive) { throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); } if (maxExclusive == int.MaxValue && minInclusive == 0) { return Next(); } if (_threadSafe) { lock (_lock) { return DoSampleInteger(minInclusive, maxExclusive); } } return DoSampleInteger(minInclusive, maxExclusive); } /// /// Fills an array with random 32-bit signed integers greater than or equal to zero and less than . /// /// The array to fill with random values. public void NextInt32s(int[] values) { if (_threadSafe) { lock (_lock) { for (var i = 0; i < values.Length; i++) { values[i] = DoSampleInteger(); } } } else { for (var i = 0; i < values.Length; i++) { values[i] = DoSampleInteger(); } } } /// /// Returns an array with random 32-bit signed integers greater than or equal to zero and less than . /// /// The size of the array to fill. public int[] NextInt32s(int count) { var values = new int[count]; NextInt32s(values); return values; } /// /// Fills an array with random numbers within a specified range. /// /// The array to fill with random values. /// The inclusive lower bound of the random number returned. /// The exclusive upper bound of the random number returned. must be greater than or equal to . public void NextInt32s(int[] values, int minInclusive, int maxExclusive) { if (minInclusive > maxExclusive) { throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); } if (maxExclusive == int.MaxValue && minInclusive == 0) { NextInt32s(values); return; } if (_threadSafe) { lock (_lock) { for (var i = 0; i < values.Length; i++) { values[i] = DoSampleInteger(minInclusive, maxExclusive); } } } else { for (var i = 0; i < values.Length; i++) { values[i] = DoSampleInteger(minInclusive, maxExclusive); } } } /// /// Returns an array with random 32-bit signed integers within the specified range. /// /// The size of the array to fill. /// The inclusive lower bound of the random number returned. /// The exclusive upper bound of the random number returned. must be greater than or equal to . public int[] NextInt32s(int count, int minInclusive, int maxExclusive) { var values = new int[count]; NextInt32s(values, minInclusive, maxExclusive); return values; } /// /// Returns an infinite sequence of random 32-bit signed integers greater than or equal to zero and less than . /// public IEnumerable NextInt32Sequence() { for (int i = 0; i < 64; i++) { yield return Next(); } var buffer = new int[64]; while (true) { NextInt32s(buffer); for (int i = 0; i < buffer.Length; i++) { yield return buffer[i]; } } } /// /// Returns an infinite sequence of random numbers within a specified range. /// /// The inclusive lower bound of the random number returned. /// The exclusive upper bound of the random number returned. must be greater than or equal to . public IEnumerable NextInt32Sequence(int minInclusive, int maxExclusive) { if (minInclusive > maxExclusive) { throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); } for (int i = 0; i < 64; i++) { yield return Next(minInclusive, maxExclusive); } var buffer = new int[64]; while (true) { NextInt32s(buffer, minInclusive, maxExclusive); for (int i = 0; i < buffer.Length; i++) { yield return buffer[i]; } } } /// /// Fills the elements of a specified array of bytes with random numbers. /// /// An array of bytes to contain random numbers. /// is null. public sealed override void NextBytes(byte[] buffer) { if (buffer == null) { throw new ArgumentNullException("buffer"); } if (_threadSafe) { lock (_lock) { DoSampleBytes(buffer); } return; } DoSampleBytes(buffer); } /// /// Returns a random number between 0.0 and 1.0. /// /// A double-precision floating point number greater than or equal to 0.0, and less than 1.0. protected sealed override double Sample() { if (_threadSafe) { lock (_lock) { return DoSample(); } } return DoSample(); } /// /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0. /// protected abstract double DoSample(); /// /// Returns a random 32-bit signed integer greater than or equal to zero and less than 2147483647 (). /// protected virtual int DoSampleInteger() { return (int)(DoSample() * int.MaxValue); } /// /// Returns a random 32-bit signed integer within the specified range. /// /// The inclusive lower bound of the random number returned. /// The exclusive upper bound of the random number returned. must be greater than or equal to . protected virtual int DoSampleInteger(int minInclusive, int maxExclusive) { return (int)(DoSample()*(maxExclusive - minInclusive)) + minInclusive; } /// /// Fills the elements of a specified array of bytes with random numbers in full range, including zero and 255 (). /// protected virtual void DoSampleBytes(byte[] buffer) { for (var i = 0; i < buffer.Length; i++) { buffer[i] = (byte)(DoSampleInteger() % 256); } } } }