diff --git a/src/Examples/RandomNumberGeneration.cs b/src/Examples/RandomNumberGeneration.cs index fe5885ae..25a7bb51 100644 --- a/src/Examples/RandomNumberGeneration.cs +++ b/src/Examples/RandomNumberGeneration.cs @@ -89,7 +89,7 @@ namespace Examples // 1. Multiplicative congruential generator using a modulus of 2^31-1 and a multiplier of 1132489760 var mcg31M1 = new Mcg31m1(1); Console.WriteLine(@"1. Generate 10 random double values using Multiplicative congruential generator with a modulus of 2^31-1 and a multiplier of 1132489760"); - var randomValues = mcg31M1.NextDouble(10); + var randomValues = mcg31M1.NextDoubles(10); for (var i = 0; i < randomValues.Length; i++) { Console.Write(randomValues[i].ToString("N") + @" "); @@ -145,11 +145,11 @@ namespace Examples Console.WriteLine(); // 6. A random number generator based on the "System.Security.Cryptography.RandomNumberGenerator" class in the .NET library - var systemCryptoRandomNumberGenerator = new SystemCryptoRandomNumberGenerator(); + var systemCrypto = new CryptoRandomSource(); Console.WriteLine(@"6. Generate 10 random decimal values using RNG based on the 'System.Security.Cryptography.RandomNumberGenerator'"); for (var i = 0; i < 10; i++) { - Console.Write(systemCryptoRandomNumberGenerator.NextDecimal().ToString("N") + @" "); + Console.Write(systemCrypto.NextDecimal().ToString("N") + @" "); } Console.WriteLine(); diff --git a/src/FSharp/Random.fs b/src/FSharp/Random.fs index ebd64895..3a05bad4 100644 --- a/src/FSharp/Random.fs +++ b/src/FSharp/Random.fs @@ -43,8 +43,8 @@ module Random = #if PORTABLE #else /// Creates a default .Net cryptographic system pRNG - let crypto () = new SystemCryptoRandomNumberGenerator() :> System.Random - let cryptoWith (threadSafe:bool) = new SystemCryptoRandomNumberGenerator(threadSafe) :> System.Random + let crypto () = new CryptoRandomSource() :> System.Random + let cryptoWith (threadSafe:bool) = new CryptoRandomSource(threadSafe) :> System.Random #endif /// Creates a Mersenne Twister 19937 pRNG with a custom seed based on uinque GUIDs diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 6b6fad24..c77fb776 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -395,14 +395,14 @@ True Resources.resx - + - - + + diff --git a/src/Numerics/Random/SystemCrypto.cs b/src/Numerics/Random/CryptoRandomSource.cs similarity index 76% rename from src/Numerics/Random/SystemCrypto.cs rename to src/Numerics/Random/CryptoRandomSource.cs index 4f29462d..b1de66b9 100644 --- a/src/Numerics/Random/SystemCrypto.cs +++ b/src/Numerics/Random/CryptoRandomSource.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2012 Math.NET +// 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 @@ -38,19 +38,19 @@ namespace MathNet.Numerics.Random /// /// A random number generator based on the class in the .NET library. /// - public class SystemCryptoRandomNumberGenerator : AbstractRandomNumberGenerator, IDisposable + public class CryptoRandomSource : RandomSource, IDisposable { - private const double Reciprocal = 1.0 / uint.MaxValue; - private readonly RandomNumberGenerator _random; + const double Reciprocal = 1.0/uint.MaxValue; + readonly RandomNumberGenerator _crypto; /// /// Construct a new random number generator with a random seed. /// /// Uses and uses the value of /// to set whether the instance is thread safe. - public SystemCryptoRandomNumberGenerator(): this(new RNGCryptoServiceProvider(), Control.ThreadSafeRandomNumberGenerators) + public CryptoRandomSource() { - _random = new RNGCryptoServiceProvider(); + _crypto = new RNGCryptoServiceProvider(); } /// @@ -58,8 +58,9 @@ namespace MathNet.Numerics.Random /// /// The to use. /// Uses the value of to set whether the instance is thread safe. - public SystemCryptoRandomNumberGenerator(RandomNumberGenerator rng) : this(rng, Control.ThreadSafeRandomNumberGenerators) + public CryptoRandomSource(RandomNumberGenerator rng) { + _crypto = rng; } /// @@ -67,8 +68,9 @@ namespace MathNet.Numerics.Random /// /// Uses /// if set to true , the class is thread safe. - public SystemCryptoRandomNumberGenerator(bool threadSafe): this(new RNGCryptoServiceProvider(), threadSafe) + public CryptoRandomSource(bool threadSafe) : base(threadSafe) { + _crypto = new RNGCryptoServiceProvider(); } /// @@ -76,13 +78,9 @@ namespace MathNet.Numerics.Random /// /// The to use. /// if set to true , the class is thread safe. - public SystemCryptoRandomNumberGenerator(RandomNumberGenerator rng, bool threadSafe) : base(threadSafe) + public CryptoRandomSource(RandomNumberGenerator rng, bool threadSafe) : base(threadSafe) { - if (rng == null) - { - throw new ArgumentNullException("rng"); - } - _random = rng; + _crypto = rng; } @@ -95,14 +93,14 @@ namespace MathNet.Numerics.Random protected override double DoSample() { var bytes = new byte[4]; - _random.GetBytes(bytes); - return BitConverter.ToUInt32(bytes, 0) * Reciprocal; + _crypto.GetBytes(bytes); + return BitConverter.ToUInt32(bytes, 0)*Reciprocal; } public void Dispose() { #if !NET35 - _random.Dispose(); + _crypto.Dispose(); #endif } } diff --git a/src/Numerics/Random/Mcg31m1.cs b/src/Numerics/Random/Mcg31m1.cs index 93fd6ef6..a37b9b5b 100644 --- a/src/Numerics/Random/Mcg31m1.cs +++ b/src/Numerics/Random/Mcg31m1.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -28,36 +28,33 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using System; - namespace MathNet.Numerics.Random { /// /// Multiplicative congruential generator using a modulus of 2^31-1 and a multiplier of 1132489760. /// - public class Mcg31m1 : AbstractRandomNumberGenerator + public class Mcg31m1 : RandomSource { - private const ulong Modulus = 2147483647; - private const ulong Multiplier = 1132489760; - private const double Reciprocal = 1.0 / Modulus; - private ulong _xn; + const ulong Modulus = 2147483647; + const ulong Multiplier = 1132489760; + const double Reciprocal = 1.0/Modulus; + ulong _xn; /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// - public Mcg31m1() : this((int) DateTime.Now.Ticks) + public Mcg31m1() : this(RandomSeed.Guid()) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. - public Mcg31m1(bool threadSafe) : this((int)DateTime.Now.Ticks, threadSafe) + public Mcg31m1(bool threadSafe) : this(RandomSeed.Guid(), threadSafe) { - } /// @@ -67,8 +64,13 @@ namespace MathNet.Numerics.Random /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public Mcg31m1(int seed) : this(seed, Control.ThreadSafeRandomNumberGenerators) + public Mcg31m1(int seed) { + if (seed == 0) + { + seed = 1; + } + _xn = (uint)seed%Modulus; } /// @@ -82,7 +84,7 @@ namespace MathNet.Numerics.Random { seed = 1; } - _xn = (uint) seed%Modulus; + _xn = (uint)seed%Modulus; } /// @@ -98,4 +100,4 @@ namespace MathNet.Numerics.Random return ret; } } -} \ No newline at end of file +} diff --git a/src/Numerics/Random/Mcg59.cs b/src/Numerics/Random/Mcg59.cs index 650c57dd..099c0c43 100644 --- a/src/Numerics/Random/Mcg59.cs +++ b/src/Numerics/Random/Mcg59.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -28,36 +28,34 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using System; - namespace MathNet.Numerics.Random { /// /// Multiplicative congruential generator using a modulus of 2^59 and a multiplier of 13^13. /// - public class Mcg59 : AbstractRandomNumberGenerator + public class Mcg59 : RandomSource { - private const double Reciprocal = 1.0 / Modulus; - private const ulong Modulus = 576460752303423488; - private const ulong Multiplier = 302875106592253; - private ulong _xn; + const double Reciprocal = 1.0/Modulus; + const ulong Modulus = 576460752303423488; + const ulong Multiplier = 302875106592253; + ulong _xn; /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// - public Mcg59() : this((int) DateTime.Now.Ticks) + public Mcg59() : this(RandomSeed.Guid()) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. - public Mcg59(bool threadSafe) : this((int)DateTime.Now.Ticks, threadSafe) + public Mcg59(bool threadSafe) : this(RandomSeed.Guid(), threadSafe) { - + } /// @@ -67,8 +65,13 @@ namespace MathNet.Numerics.Random /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public Mcg59(int seed) : this(seed, Control.ThreadSafeRandomNumberGenerators) + public Mcg59(int seed) { + if (seed == 0) + { + seed = 1; + } + _xn = (uint)seed%Modulus; } /// @@ -79,11 +82,11 @@ namespace MathNet.Numerics.Random /// if set to true , the class is thread safe. public Mcg59(int seed, bool threadSafe) : base(threadSafe) { - if( seed == 0) + if (seed == 0) { seed = 1; } - _xn = (uint) seed % Modulus; + _xn = (uint)seed%Modulus; } /// @@ -94,9 +97,9 @@ namespace MathNet.Numerics.Random /// protected override double DoSample() { - double ret = _xn * Reciprocal; - _xn = (_xn * Multiplier) % Modulus; + double ret = _xn*Reciprocal; + _xn = (_xn*Multiplier)%Modulus; return ret; } } -} \ No newline at end of file +} diff --git a/src/Numerics/Random/MersenneTwister.cs b/src/Numerics/Random/MersenneTwister.cs index c23a8c11..1c8efc2c 100644 --- a/src/Numerics/Random/MersenneTwister.cs +++ b/src/Numerics/Random/MersenneTwister.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -66,7 +66,6 @@ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) */ -using System; using System.Threading; namespace MathNet.Numerics.Random @@ -74,70 +73,70 @@ namespace MathNet.Numerics.Random /// /// Random number generator using Mersenne Twister 19937 algorithm. /// - public class MersenneTwister : AbstractRandomNumberGenerator, IDisposable + public class MersenneTwister : RandomSource { /// /// Mersenne twister constant. /// - private const uint LowerMask = 0x7fffffff; + const uint LowerMask = 0x7fffffff; /// /// Mersenne twister constant. /// - private const int M = 397; + const int M = 397; /// /// Mersenne twister constant. /// - private const uint MatrixA = 0x9908b0df; + const uint MatrixA = 0x9908b0df; /// /// Mersenne twister constant. /// - private const int N = 624; + const int N = 624; /// /// Mersenne twister constant. /// - private const double Reciprocal = 1.0/4294967296.0; + const double Reciprocal = 1.0/4294967296.0; /// /// Mersenne twister constant. /// - private const uint UpperMask = 0x80000000; + const uint UpperMask = 0x80000000; /// /// Mersenne twister constant. /// - private static readonly uint[] Mag01 = {0x0U, MatrixA}; + static readonly uint[] Mag01 = { 0x0U, MatrixA }; /// /// Mersenne twister constant. /// - private readonly uint[] _mt = new uint[624]; + readonly uint[] _mt = new uint[624]; /// /// Mersenne twister constant. /// - private int _mti = N + 1; + int _mti = N + 1; /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public MersenneTwister() : this((int) DateTime.Now.Ticks) + public MersenneTwister() : this(RandomSeed.Guid()) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. - public MersenneTwister(bool threadSafe) : this((int) DateTime.Now.Ticks, threadSafe) + public MersenneTwister(bool threadSafe) : this(RandomSeed.Guid(), threadSafe) { } @@ -147,8 +146,9 @@ namespace MathNet.Numerics.Random /// The seed value. /// Uses the value of to /// set whether the instance is thread safe. - public MersenneTwister(int seed) : this(seed, Control.ThreadSafeRandomNumberGenerators) + public MersenneTwister(int seed) { + init_genrand((uint)seed); } /// @@ -190,7 +190,7 @@ namespace MathNet.Numerics.Random get { return DefaultInstance.Value; } } #endif - + /*/// /// Initializes a new instance of the class. /// @@ -211,12 +211,12 @@ namespace MathNet.Numerics.Random */ /* initializes _mt[_n] with a seed */ - private void init_genrand(uint s) + void init_genrand(uint s) { _mt[0] = s & 0xffffffff; for (_mti = 1; _mti < N; _mti++) { - _mt[_mti] = (1812433253*(_mt[_mti - 1] ^ (_mt[_mti - 1] >> 30)) + (uint) _mti); + _mt[_mti] = (1812433253*(_mt[_mti - 1] ^ (_mt[_mti - 1] >> 30)) + (uint)_mti); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array _mt[]. */ @@ -231,7 +231,7 @@ namespace MathNet.Numerics.Random /* init_key is the array for initializing keys */ /* slight change for C++, 2004/2/26 */ - /* private void init_by_array(uint[] init_key) + /* private void init_by_array(uint[] init_key) { uint key_length = (uint) init_key.Length; init_genrand(19650218); @@ -268,7 +268,7 @@ namespace MathNet.Numerics.Random /* generates a random number on [0,0xffffffff]-interval */ - private uint genrand_int32() + uint genrand_int32() { uint y; @@ -317,10 +317,10 @@ namespace MathNet.Numerics.Random /// protected override double DoSample() { - return genrand_int32() * Reciprocal; + return genrand_int32()*Reciprocal; } - /* /// + /* /// /// Generates a random number on [0,1) with 53-bit resolution. /// /// A random number on [0,1) with 53-bit resolution. @@ -329,17 +329,5 @@ namespace MathNet.Numerics.Random ulong a = genrand_int32() >> 5, b = genrand_int32() >> 6; return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); }*/ - - #region IDisposable Members - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - //do nothing in the managed version. - } - - #endregion } -} \ No newline at end of file +} diff --git a/src/Numerics/Random/Mrg32k3a.cs b/src/Numerics/Random/Mrg32k3a.cs index b54812f2..a8cd9a44 100644 --- a/src/Numerics/Random/Mrg32k3a.cs +++ b/src/Numerics/Random/Mrg32k3a.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -36,40 +36,40 @@ namespace MathNet.Numerics.Random /// A 32-bit combined multiple recursive generator with 2 components of order 3. /// ///Based off of P. L'Ecuyer, "Combined Multiple Recursive Random Number Generators," Operations Research, 44, 5 (1996), 816--822. - public class Mrg32k3a : AbstractRandomNumberGenerator + public class Mrg32k3a : RandomSource { - private const double A12 = 1403580; - private const double A13 = 810728; - private const double A21 = 527612; - private const double A23 = 1370589; - private const double Modulus1 = 4294967087; - private const double Modulus2 = 4294944443; + const double A12 = 1403580; + const double A13 = 810728; + const double A21 = 527612; + const double A23 = 1370589; + const double Modulus1 = 4294967087; + const double Modulus2 = 4294944443; - private const double Reciprocal = 1.0 / Modulus1; - private double _xn1 = 1; - private double _xn2 = 1; - private double _xn3; - private double _yn1 = 1; - private double _yn2 = 1; - private double _yn3 = 1; + const double Reciprocal = 1.0/Modulus1; + double _xn1 = 1; + double _xn2 = 1; + double _xn3; + double _yn1 = 1; + double _yn2 = 1; + double _yn3 = 1; /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public Mrg32k3a() : this((int)DateTime.Now.Ticks) + public Mrg32k3a() : this(RandomSeed.Guid()) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. - public Mrg32k3a(bool threadSafe) : this((int)DateTime.Now.Ticks, threadSafe) + public Mrg32k3a(bool threadSafe) : this(RandomSeed.Guid(), threadSafe) { } @@ -80,8 +80,13 @@ namespace MathNet.Numerics.Random /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public Mrg32k3a(int seed) : this(seed, Control.ThreadSafeRandomNumberGenerators) + public Mrg32k3a(int seed) { + if (seed == 0) + { + seed = 1; + } + _xn3 = (uint)seed; } /// @@ -108,7 +113,7 @@ namespace MathNet.Numerics.Random protected override double DoSample() { double xn = A12*_xn2 - A13*_xn3; - double k = (long) (xn/Modulus1); + double k = (long)(xn/Modulus1); xn -= k*Modulus1; if (xn < 0) { @@ -116,7 +121,7 @@ namespace MathNet.Numerics.Random } double yn = A21*_yn1 - A23*_yn3; - k = (long) (yn/Modulus2); + k = (long)(yn/Modulus2); yn -= k*Modulus2; if (yn < 0) { @@ -136,4 +141,4 @@ namespace MathNet.Numerics.Random return (xn - yn)*Reciprocal; } } -} \ No newline at end of file +} diff --git a/src/Numerics/Random/Palf.cs b/src/Numerics/Random/Palf.cs index 01ff002a..efa4e036 100644 --- a/src/Numerics/Random/Palf.cs +++ b/src/Numerics/Random/Palf.cs @@ -43,7 +43,7 @@ namespace MathNet.Numerics.Random /// It uses the modulus 232 and by default the "lags" 418 and 1279. Some popular pairs are presented on /// Wikipedia - Lagged Fibonacci generator. /// - public class Palf : AbstractRandomNumberGenerator + public class Palf : RandomSource { /// /// Default value for the ShortLag @@ -62,23 +62,21 @@ namespace MathNet.Numerics.Random /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public Palf() - : this((int) DateTime.Now.Ticks) + public Palf() : this(RandomSeed.Guid(), Control.ThreadSafeRandomNumberGenerators, DefaultShortLag, DefaultLongLag) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. - public Palf(bool threadSafe) - : this((int) DateTime.Now.Ticks, threadSafe, DefaultShortLag, DefaultLongLag) + public Palf(bool threadSafe) : this(RandomSeed.Guid(), threadSafe, DefaultShortLag, DefaultLongLag) { } @@ -89,8 +87,7 @@ namespace MathNet.Numerics.Random /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public Palf(int seed) - : this(seed, Control.ThreadSafeRandomNumberGenerators, DefaultShortLag, DefaultLongLag) + public Palf(int seed) : this(seed, Control.ThreadSafeRandomNumberGenerators, DefaultShortLag, DefaultLongLag) { } @@ -101,8 +98,7 @@ namespace MathNet.Numerics.Random /// if set to true, the class is thread safe. /// The ShortLag value /// TheLongLag value - public Palf(int seed, bool threadSafe, int shortLag, int longLag) - : base(threadSafe) + public Palf(int seed, bool threadSafe, int shortLag, int longLag) : base(threadSafe) { if (shortLag < 1) { @@ -135,7 +131,7 @@ namespace MathNet.Numerics.Random var gen = new MersenneTwister(seed, threadSafe); for (var j = 0; j < LongLag; ++j) { - _x[j] = (uint) (gen.NextDouble()*uint.MaxValue); + _x[j] = (uint)(gen.NextDouble()*uint.MaxValue); } _i = LongLag; @@ -171,21 +167,21 @@ namespace MathNet.Numerics.Random void Fill() { CommonParallel.For(0, Control.NumberOfParallelWorkerThreads, (u, v) => + { + for (int index = u; index < v; index++) { - for (int index = u; index < v; index++) + // Two loops to avoid costly modulo operations + for (var j = index; j < ShortLag; j = j + Control.NumberOfParallelWorkerThreads) + { + _x[j] += _x[j + (LongLag - ShortLag)]; + } + + for (var j = ShortLag + index; j < LongLag; j = j + Control.NumberOfParallelWorkerThreads) { - // Two loops to avoid costly modulo operations - for (var j = index; j < ShortLag; j = j + Control.NumberOfParallelWorkerThreads) - { - _x[j] += _x[j + (LongLag - ShortLag)]; - } - - for (var j = ShortLag + index; j < LongLag; j = j + Control.NumberOfParallelWorkerThreads) - { - _x[j] += _x[j - ShortLag - index]; - } + _x[j] += _x[j - ShortLag - index]; } - }); + } + }); _i = 0; } @@ -203,7 +199,7 @@ namespace MathNet.Numerics.Random } var x = _x[_i++]; - return (int) (x >> 1)*IntToDoubleMultiplier; + return (int)(x >> 1)*IntToDoubleMultiplier; } } } diff --git a/src/Numerics/Random/SystemRandomExtensions.cs b/src/Numerics/Random/RandomExtensions.cs similarity index 99% rename from src/Numerics/Random/SystemRandomExtensions.cs rename to src/Numerics/Random/RandomExtensions.cs index 4b837d5d..e7af4a92 100644 --- a/src/Numerics/Random/SystemRandomExtensions.cs +++ b/src/Numerics/Random/RandomExtensions.cs @@ -36,7 +36,7 @@ namespace MathNet.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 SystemRandomExtensions + public static class RandomExtensions { /// /// Returns a nonnegative random number less than . diff --git a/src/Numerics/Random/AbstractRandomNumberGenerator.cs b/src/Numerics/Random/RandomSource.cs similarity index 62% rename from src/Numerics/Random/AbstractRandomNumberGenerator.cs rename to src/Numerics/Random/RandomSource.cs index f80dfd9a..2534ada7 100644 --- a/src/Numerics/Random/AbstractRandomNumberGenerator.cs +++ b/src/Numerics/Random/RandomSource.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -28,52 +28,63 @@ // OTHER DEALINGS IN THE SOFTWARE. // +using System; using MathNet.Numerics.Properties; namespace MathNet.Numerics.Random { - using System; - /// - /// Abstract class for random number generators. This class introduces a layer between + /// 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 AbstractRandomNumberGenerator : Random + public class RandomSource : System.Random { - /// - /// A delegate type that represents a method that generates random numbers. - /// - /// Randomly distributed numbers. - private delegate double SampleMethod(); + readonly bool _threadSafe; + readonly object _lock = new object(); /// - /// The method that actually generates samples. + /// Initializes a new instance of the class using + /// the value of to set whether + /// the instance is thread safe or not. /// - private readonly SampleMethod _sampleMethod; + public RandomSource() : base(RandomSeed.Guid()) + { + _threadSafe = Control.ThreadSafeRandomNumberGenerators; + } /// - /// The object that will be locked for thread safety. + /// Initializes a new instance of the class. /// - private readonly object _lock = new object(); + /// if set to true , the class is thread safe. + /// Thread safe instances are two and half times slower than non-thread + /// safe classes. + public RandomSource(bool threadSafe) : base(RandomSeed.Guid()) + { + _threadSafe = threadSafe; + } /// - /// Initializes a new instance of the class using + /// Initializes a new instance of the class using /// the value of to set whether /// the instance is thread safe or not. /// - protected AbstractRandomNumberGenerator() : this(Control.ThreadSafeRandomNumberGenerators) + /// The seed value. + public RandomSource(int systemRandomSeed) : base(systemRandomSeed) { + _threadSafe = Control.ThreadSafeRandomNumberGenerators; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// + /// The seed value. /// if set to true , the class is thread safe. /// Thread safe instances are two and half times slower than non-thread /// safe classes. - protected AbstractRandomNumberGenerator(bool threadSafe) + public RandomSource(int systemRandomSeed, bool threadSafe) : base(systemRandomSeed) { - _sampleMethod = threadSafe ? (SampleMethod)ThreadSafeSample : DoSample; + _threadSafe = threadSafe; } /// @@ -84,7 +95,7 @@ namespace MathNet.Numerics.Random /// An array of uniformly distributed random doubles in the interval [0.0,1.0]. /// /// if n is not greater than 0. - public double[] NextDouble(int n) + public double[] NextDoubles(int n) { if (n < 1) { @@ -92,11 +103,23 @@ namespace MathNet.Numerics.Random } var ret = new double[n]; - for (var i = 0; i < ret.Length; i++) + if (_threadSafe) { - ret[i] = Sample(); + lock (_lock) + { + for (var i = 0; i < ret.Length; i++) + { + ret[i] = DoSample(); + } + } + } + else + { + for (var i = 0; i < ret.Length; i++) + { + ret[i] = DoSample(); + } } - return ret; } @@ -106,9 +129,17 @@ namespace MathNet.Numerics.Random /// /// A 32-bit signed integer greater than or equal to zero and less than . /// - public override int Next() + public override sealed int Next() { - return (int)(Sample() * int.MaxValue); + if (_threadSafe) + { + lock (_lock) + { + return (int)(DoSample()*int.MaxValue); + } + } + + return (int)(DoSample()*int.MaxValue); } /// @@ -117,14 +148,22 @@ namespace MathNet.Numerics.Random /// The exclusive upper bound of the random number returned. /// A 32-bit signed integer less than . /// is negative. - public override int Next(int maxValue) + public override sealed int Next(int maxValue) { if (maxValue <= 0) { throw new ArgumentOutOfRangeException(Resources.ArgumentMustBePositive); } - return (int)(Sample() * maxValue); + if (_threadSafe) + { + lock (_lock) + { + return (int)(DoSample()*maxValue); + } + } + + return (int)(DoSample()*maxValue); } /// @@ -136,14 +175,22 @@ namespace MathNet.Numerics.Random /// 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 override int Next(int minValue, int maxValue) + public override sealed int Next(int minValue, int maxValue) { if (minValue > maxValue) { throw new ArgumentOutOfRangeException(Resources.ArgumentMinValueGreaterThanMaxValue); } - return (int)(Sample() * (maxValue - minValue)) + minValue; + if (_threadSafe) + { + lock (_lock) + { + return (int)(DoSample()*(maxValue - minValue)) + minValue; + } + } + + return (int)(DoSample()*(maxValue - minValue)) + minValue; } /// @@ -158,9 +205,21 @@ namespace MathNet.Numerics.Random throw new ArgumentNullException("buffer"); } + if (_threadSafe) + { + lock (_lock) + { + for (var i = 0; i < buffer.Length; i++) + { + buffer[i] = (byte)(((int)(DoSample()*int.MaxValue))%256); + } + } + return; + } + for (var i = 0; i < buffer.Length; i++) { - buffer[i] = (byte)(Next() % 256); + buffer[i] = (byte)(((int)(DoSample()*int.MaxValue))%256); } } @@ -170,14 +229,22 @@ namespace MathNet.Numerics.Random /// A double-precision floating point number greater than or equal to 0.0, and less than 1.0. protected override double Sample() { - return _sampleMethod(); + if (_threadSafe) + { + lock (_lock) + { + return DoSample(); + } + } + + return DoSample(); } /// /// Thread safe version of which 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 - private double ThreadSafeSample() + double ThreadSafeSample() { lock (_lock) { @@ -191,6 +258,9 @@ namespace MathNet.Numerics.Random /// /// A double-precision floating point number greater than or equal to 0.0, and less than 1.0. /// - protected abstract double DoSample(); + protected virtual double DoSample() + { + return base.Sample(); + } } -} \ No newline at end of file +} diff --git a/src/Numerics/Random/WH1982.cs b/src/Numerics/Random/WH1982.cs index d4e410fd..5b64e386 100644 --- a/src/Numerics/Random/WH1982.cs +++ b/src/Numerics/Random/WH1982.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -28,8 +28,6 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using System; - namespace MathNet.Numerics.Random { /// @@ -38,33 +36,32 @@ namespace MathNet.Numerics.Random /// See: Wichmann, B. A. & Hill, I. D. (1982), "Algorithm AS 183: /// An efficient and portable pseudo-random number generator". Applied Statistics 31 (1982) 188-190 /// - public class WH1982 : AbstractRandomNumberGenerator + public class WH1982 : RandomSource { - private const uint Modx = 30269; - private const double ModxRecip = 1.0/Modx; - private const uint Mody = 30307; - private const double ModyRecip = 1.0/Mody; - private const uint Modz = 30323; - private const double ModzRecip = 1.0/Modz; - private uint _xn; - private uint _yn = 1; - private uint _zn = 1; + const uint Modx = 30269; + const double ModxRecip = 1.0/Modx; + const uint Mody = 30307; + const double ModyRecip = 1.0/Mody; + const uint Modz = 30323; + const double ModzRecip = 1.0/Modz; + uint _xn; + uint _yn = 1; + uint _zn = 1; /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// - public WH1982() : this((int) DateTime.Now.Ticks) + public WH1982() : this(RandomSeed.Guid()) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. - public WH1982(bool threadSafe) - : this((int) DateTime.Now.Ticks, threadSafe) + public WH1982(bool threadSafe) : this(RandomSeed.Guid(), threadSafe) { } @@ -75,8 +72,13 @@ namespace MathNet.Numerics.Random /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public WH1982(int seed) : this(seed, Control.ThreadSafeRandomNumberGenerators) + public WH1982(int seed) { + if (seed == 0) + { + seed = 1; + } + _xn = (uint)seed%Modx; } /// @@ -92,7 +94,7 @@ namespace MathNet.Numerics.Random { seed = 1; } - _xn = (uint) seed%Modx; + _xn = (uint)seed%Modx; } /// @@ -108,8 +110,8 @@ namespace MathNet.Numerics.Random _zn = (170*_zn)%Modz; double w = _xn*ModxRecip + _yn*ModyRecip + _zn*ModzRecip; - w -= (int) w; + w -= (int)w; return w; } } -} \ No newline at end of file +} diff --git a/src/Numerics/Random/WH2006.cs b/src/Numerics/Random/WH2006.cs index 94e5f27b..e0bf71db 100644 --- a/src/Numerics/Random/WH2006.cs +++ b/src/Numerics/Random/WH2006.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -28,8 +28,6 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using System; - namespace MathNet.Numerics.Random { /// @@ -38,36 +36,35 @@ namespace MathNet.Numerics.Random /// See: Wichmann, B. A. & Hill, I. D. (2006), "Generating good pseudo-random numbers". /// Computational Statistics & Data Analysis 51:3 (2006) 1614-1622 /// - public class WH2006 : AbstractRandomNumberGenerator + public class WH2006 : RandomSource { - private const uint Modw = 2147483123; - private const double ModwRecip = 1.0/Modw; - private const uint Modx = 2147483579; - private const double ModxRecip = 1.0/Modx; - private const uint Mody = 2147483543; - private const double ModyRecip = 1.0/Mody; - private const uint Modz = 2147483423; - private const double ModzRecip = 1.0/Modz; - private ulong _wn = 1; - private ulong _xn; - private ulong _yn = 1; - private ulong _zn = 1; + const uint Modw = 2147483123; + const double ModwRecip = 1.0/Modw; + const uint Modx = 2147483579; + const double ModxRecip = 1.0/Modx; + const uint Mody = 2147483543; + const double ModyRecip = 1.0/Mody; + const uint Modz = 2147483423; + const double ModzRecip = 1.0/Modz; + ulong _wn = 1; + ulong _xn; + ulong _yn = 1; + ulong _zn = 1; /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// - public WH2006() : this((int) DateTime.Now.Ticks) + public WH2006() : this(RandomSeed.Guid()) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. - public WH2006(bool threadSafe) - : this((int) DateTime.Now.Ticks, threadSafe) + public WH2006(bool threadSafe) : this(RandomSeed.Guid(), threadSafe) { } @@ -78,8 +75,13 @@ namespace MathNet.Numerics.Random /// If the seed value is zero, it is set to one. Uses the /// value of to /// set whether the instance is thread safe. - public WH2006(int seed) : this(seed, Control.ThreadSafeRandomNumberGenerators) + public WH2006(int seed) { + if (seed == 0) + { + seed = 1; + } + _xn = (uint)seed%Modx; } /// @@ -88,14 +90,13 @@ namespace MathNet.Numerics.Random /// The seed value. /// The seed is set to 1, if the zero is used as the seed. /// if set to true , the class is thread safe. - public WH2006(int seed, bool threadSafe) - : base(threadSafe) + public WH2006(int seed, bool threadSafe) : base(threadSafe) { if (seed == 0) { seed = 1; } - _xn = (uint) seed%Modx; + _xn = (uint)seed%Modx; } /// @@ -112,8 +113,8 @@ namespace MathNet.Numerics.Random _wn = 33000*_wn%Modw; double u = _xn*ModxRecip + _yn*ModyRecip + _zn*ModzRecip + _wn*ModwRecip; - u -= (int) u; + u -= (int)u; return u; } } -} \ No newline at end of file +} diff --git a/src/Numerics/Random/Xorshift.cs b/src/Numerics/Random/Xorshift.cs index da38207c..65613703 100644 --- a/src/Numerics/Random/Xorshift.cs +++ b/src/Numerics/Random/Xorshift.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2010 Math.NET +// 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 @@ -28,8 +28,8 @@ // OTHER DEALINGS IN THE SOFTWARE. // -using MathNet.Numerics.Properties; using System; +using MathNet.Numerics.Properties; namespace MathNet.Numerics.Random { @@ -38,61 +38,61 @@ namespace MathNet.Numerics.Random /// Xn = a * Xn−3 + c mod 2^32 /// http://www.jstatsoft.org/v08/i14/paper /// - public class Xorshift : AbstractRandomNumberGenerator + public class Xorshift : RandomSource { /// /// The default value for X1. /// - private const uint YSeed = 362436069; + const uint YSeed = 362436069; /// /// The default value for X2. /// - private const uint ZSeed = 77465321; + const uint ZSeed = 77465321; /// /// The default value for the multiplier. /// - private const uint ASeed = 916905990; + const uint ASeed = 916905990; /// /// The default value for the carry over. /// - private const uint CSeed = 13579; + const uint CSeed = 13579; /// /// The multiplier to compute a double-precision floating point number [0, 1) /// - private const double UlongToDoubleMultiplier = 1.0 / (uint.MaxValue + 1.0); + const double UlongToDoubleMultiplier = 1.0/(uint.MaxValue + 1.0); /// /// Seed or last but three unsigned random number. /// - private ulong _x; + ulong _x; /// /// Last but two unsigned random number. /// - private ulong _y; + ulong _y; /// /// Last but one unsigned random number. /// - private ulong _z; + ulong _z; /// /// The value of the carry over. /// - private ulong _c; + ulong _c; /// /// The multiplier. /// - private readonly ulong _a; + readonly ulong _a; /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// If the seed value is zero, it is set to one. Uses the /// value of to @@ -104,13 +104,13 @@ namespace MathNet.Numerics.Random /// X1 = 77465321 /// X2 = 362436069 /// - public Xorshift() : this((int)DateTime.Now.Ticks) + public Xorshift() : this(RandomSeed.Guid()) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// The multiply value /// The initial carry value. @@ -121,14 +121,13 @@ namespace MathNet.Numerics.Random /// set whether the instance is thread safe. /// Note: must be less than . /// - public Xorshift(long a, long c, long x1, long x2) - : this((int)DateTime.Now.Ticks, a, c, x1, x2) + public Xorshift(long a, long c, long x1, long x2) : this(RandomSeed.Guid(), a, c, x1, x2) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. /// @@ -139,14 +138,13 @@ namespace MathNet.Numerics.Random /// X1 = 77465321 /// X2 = 362436069 /// - public Xorshift(bool threadSafe) - : this((int)DateTime.Now.Ticks, threadSafe) + public Xorshift(bool threadSafe) : this(RandomSeed.Guid(), threadSafe) { } /// /// Initializes a new instance of the class using - /// the current time as the seed. + /// a seed based on time and unique GUIDs. /// /// if set to true , the class is thread safe. /// The multiply value @@ -154,11 +152,10 @@ namespace MathNet.Numerics.Random /// The initial value if X1. /// The initial value if X2. /// must be less than . - public Xorshift(bool threadSafe, long a, long c, long x1, long x2) - : this((int)DateTime.Now.Ticks, threadSafe, a, c, x1, x2) + public Xorshift(bool threadSafe, long a, long c, long x1, long x2) : this(RandomSeed.Guid(), threadSafe, a, c, x1, x2) { } - + /// /// Initializes a new instance of the class. /// @@ -189,8 +186,7 @@ namespace MathNet.Numerics.Random /// The initial value if X1. /// The initial value if X2. /// must be less than . - public Xorshift(int seed, long a, long c, long x1, long x2) - : this(seed, Control.ThreadSafeRandomNumberGenerators, a, c, x1, x2) + public Xorshift(int seed, long a, long c, long x1, long x2) : this(seed, Control.ThreadSafeRandomNumberGenerators, a, c, x1, x2) { } @@ -231,8 +227,7 @@ namespace MathNet.Numerics.Random /// The initial value if X1. /// The initial value if X2. /// must be less than . - public Xorshift(int seed, bool threadSafe, long a, long c, long x1, long x2) - : base(threadSafe) + public Xorshift(int seed, bool threadSafe, long a, long c, long x1, long x2) : base(threadSafe) { if (seed == 0) { @@ -259,12 +254,12 @@ namespace MathNet.Numerics.Random /// protected override double DoSample() { - var t = (_a * _x) + _c; + var t = (_a*_x) + _c; _x = _y; _y = _z; _c = t >> 32; _z = t & 0xffffffff; - return _z * UlongToDoubleMultiplier; + return _z*UlongToDoubleMultiplier; } } } diff --git a/src/UnitTests/Random/SystemCryptoTests.cs b/src/UnitTests/Random/SystemCryptoTests.cs index 89e3a007..c1bd2955 100644 --- a/src/UnitTests/Random/SystemCryptoTests.cs +++ b/src/UnitTests/Random/SystemCryptoTests.cs @@ -34,13 +34,13 @@ namespace MathNet.Numerics.UnitTests.Random /// Tests for a random number generator based on the class in the .NET library /// [TestFixture, Category("Random")] - public class SystemCryptoRandomNumberGeneratorTests : RandomTests + public class CryptoRandomSourceTests : RandomTests { /// /// Initializes a new instance of the SystemCryptoRandomNumberGeneratorTests class. /// - public SystemCryptoRandomNumberGeneratorTests() - : base(typeof(SystemCryptoRandomNumberGenerator)) + public CryptoRandomSourceTests() + : base(typeof(CryptoRandomSource)) { } }