diff --git a/src/FSharp/Random.fs b/src/FSharp/Random.fs index f6253d2d..24ee548e 100644 --- a/src/FSharp/Random.fs +++ b/src/FSharp/Random.fs @@ -37,78 +37,67 @@ module Random = let shared = SystemRandomSource.Default :> System.Random /// Default sampling, efficient but without custom seed (uses robust seeds internally) - let samples length = SystemRandomSource.Samples(length) - let sampleSeq () = SystemRandomSource.SampleSequence() + let inline doubles (length:int) = SystemRandomSource.Doubles(length) + let inline doubleSeq () = SystemRandomSource.DoubleSequence() + let inline doubleFill (values:double[]) = SystemRandomSource.Doubles(values) - /// Creates a default .Net system pRNG with a custom seed based on uinque GUIDs - let system () = new SystemRandomSource() :> System.Random - let systemSeed (seed:int) = new SystemRandomSource(seed) :> System.Random - let systemSamples (seed:int) length = SystemRandomSource.Samples(length, seed) - let systemSampleSeq (seed:int) = SystemRandomSource.SampleSequence(seed) + let inline doublesSeed (seed:int) (length:int) = SystemRandomSource.Doubles(length, seed) + let inline doubleSeqSeed (seed:int) = SystemRandomSource.DoubleSequence(seed) + let inline doubleFillSeed (seed:int) (values:double[]) = SystemRandomSource.Doubles(values, seed) + + /// Creates a default .Net system pRNG with a robust seed + let systemShared = shared + let inline system () = SystemRandomSource() :> System.Random + let inline systemSeed (seed:int) = SystemRandomSource(seed) :> System.Random #if PORTABLE #else /// Creates a default .Net cryptographic system pRNG - let crypto () = new CryptoRandomSource() :> System.Random - let cryptoWith (threadSafe:bool) = new CryptoRandomSource(threadSafe) :> System.Random - let cryptoSamples length = CryptoRandomSource.Samples(length) - let cryptoSampleSeq () = CryptoRandomSource.SampleSequence() + let inline crypto () = new CryptoRandomSource() :> System.Random + let inline cryptoWith (threadSafe:bool) = new CryptoRandomSource(threadSafe) :> System.Random + let inline cryptoDoubles length = CryptoRandomSource.Doubles(length) + let inline cryptoDoubleSeq () = CryptoRandomSource.DoubleSequence() #endif - /// Creates a Mersenne Twister 19937 pRNG with a custom seed based on uinque GUIDs - let mersenneTwister () = new MersenneTwister() :> System.Random - let mersenneTwisterSeed (seed:int) = new MersenneTwister(seed) :> System.Random - let mersenneTwisterWith seed threadSafe = new MersenneTwister(seed, threadSafe) :> System.Random - let mersenneTwisterSamples (seed:int) length = MersenneTwister.Samples(length, seed) - let mersenneTwisterSampleSeq (seed:int) = MersenneTwister.SampleSequence(seed) + /// Creates a Mersenne Twister 19937 pRNG with a robust seed + let mersenneTwisterShared = MersenneTwister.Default :> System.Random + let inline mersenneTwister () = MersenneTwister() :> System.Random + let inline mersenneTwisterSeed (seed:int) = MersenneTwister(seed) :> System.Random + let inline mersenneTwisterWith (seed:int) threadSafe = MersenneTwister(seed, threadSafe) :> System.Random - /// Creates a multiply-with-carry Xorshift (Xn = a * Xn−3 + c mod 2^32) pRNG with a custom seed based on uinque GUIDs - let xorshift () = new Xorshift() :> System.Random - let xorshiftSeed (seed:int) = new Xorshift(seed) :> System.Random - let xorshiftWith seed threadSafe = new Xorshift(seed, threadSafe) :> System.Random - let xorshiftCustom seed threadSafe a c x1 x2 = new Xorshift(seed, threadSafe, a, c, x1, x2) :> System.Random - let xorshiftSamples (seed:int) length = Xorshift.Samples(length, seed) - let xorshiftSampleSeq (seed:int) = Xorshift.SampleSequence(seed) + /// Creates a multiply-with-carry Xorshift (Xn = a * Xn−3 + c mod 2^32) pRNG with a robust seed + let inline xorshift () = Xorshift() :> System.Random + let inline xorshiftSeed (seed:int) = Xorshift(seed) :> System.Random + let inline xorshiftWith (seed:int) threadSafe = Xorshift(seed, threadSafe) :> System.Random + let inline xorshiftCustom (seed:int) threadSafe a c x1 x2 = Xorshift(seed, threadSafe, a, c, x1, x2) :> System.Random - /// Creates a Wichmann-Hill’s 1982 combined multiplicative congruential pRNG with a custom seed based on uinque GUIDs - let wh1982 () = new WH1982() :> System.Random - let wh1982Seed (seed:int) = new WH1982(seed) :> System.Random - let wh1982With seed threadSafe = new WH1982(seed, threadSafe) :> System.Random - let wh1982Samples (seed:int) length = WH1982.Samples(length, seed) - let wh1982SampleSeq (seed:int) = WH1982.SampleSequence(seed) + /// Creates a Wichmann-Hill’s 1982 combined multiplicative congruential pRNG with a robust seed + let inline wh1982 () = WH1982() :> System.Random + let inline wh1982Seed (seed:int) = WH1982(seed) :> System.Random + let inline wh1982With (seed:int) threadSafe = WH1982(seed, threadSafe) :> System.Random - /// Creates a Wichmann-Hill’s 2006 combined multiplicative congruential pRNG with a custom seed based on uinque GUIDs - let wh2006 () = new WH2006() :> System.Random - let wh2006Seed (seed:int) = new WH2006(seed) :> System.Random - let wh2006With seed threadSafe = new WH2006(seed, threadSafe) :> System.Random - let wh2006Samples (seed:int) length = WH2006.Samples(length, seed) - let wh2006SampleSeq (seed:int) = WH2006.SampleSequence(seed) + /// Creates a Wichmann-Hill’s 2006 combined multiplicative congruential pRNG with a robust seed + let inline wh2006 () = WH2006() :> System.Random + let inline wh2006Seed (seed:int) = WH2006(seed) :> System.Random + let inline wh2006With (seed:int) threadSafe = WH2006(seed, threadSafe) :> System.Random - /// Creates a Parallel Additive Lagged Fibonacci pRNG with a custom seed based on uinque GUIDs - let palf () = new Palf() :> System.Random - let palfSeed (seed:int) = new Palf(seed) :> System.Random - let palfWith seed threadSafe = new Palf(seed, threadSafe, 418, 1279) :> System.Random - let palfCustom seed threadSafe shortLag longLag = new Palf(seed, threadSafe, shortLag, longLag) :> System.Random - let palfSamples (seed:int) length = Palf.Samples(length, seed) - let palfSampleSeq (seed:int) = Palf.SampleSequence(seed) + /// Creates a Parallel Additive Lagged Fibonacci pRNG with a robust seed + let inline palf () = Palf() :> System.Random + let inline palfSeed (seed:int) = Palf(seed) :> System.Random + let inline palfWith (seed:int) threadSafe = Palf(seed, threadSafe, 418, 1279) :> System.Random + let inline palfCustom (seed:int) threadSafe shortLag longLag = Palf(seed, threadSafe, shortLag, longLag) :> System.Random - /// Creates a Multiplicative congruential generator using a modulus of 2^59 and a multiplier of 13^13 pRNG with a custom seed based on uinque GUIDs - let mcg59 () = new Mcg59() :> System.Random - let mcg59Seed (seed:int) = new Mcg59(seed) :> System.Random - let mcg59With seed threadSafe = new Mcg59(seed, threadSafe) :> System.Random - let mcg59Samples (seed:int) length = Mcg59.Samples(length, seed) - let mcg59SampleSeq (seed:int) = Mcg59.SampleSequence(seed) + /// Creates a Multiplicative congruential generator using a modulus of 2^59 and a multiplier of 13^13 pRNG with a robust seed + let inline mcg59 () = Mcg59() :> System.Random + let inline mcg59Seed (seed:int) = Mcg59(seed) :> System.Random + let inline mcg59With (seed:int) threadSafe = Mcg59(seed, threadSafe) :> System.Random - /// Creates a Multiplicative congruential generator using a modulus of 2^31-1 and a multiplier of 1132489760 pRNG with a custom seed based on uinque GUIDs - let mcg31m1 () = new Mcg31m1() :> System.Random - let mcg31m1Seed (seed:int) = new Mcg31m1(seed) :> System.Random - let mcg31m1With seed threadSafe = new Mcg31m1(seed, threadSafe) :> System.Random - let mcg31m1Samples (seed:int) length = Mcg31m1.Samples(length, seed) - let mcg31m1SampleSeq (seed:int) = Mcg31m1.SampleSequence(seed) + /// Creates a Multiplicative congruential generator using a modulus of 2^31-1 and a multiplier of 1132489760 pRNG with a robust seed + let inline mcg31m1 () = Mcg31m1() :> System.Random + let inline mcg31m1Seed (seed:int) = Mcg31m1(seed) :> System.Random + let inline mcg31m1With (seed:int) threadSafe = Mcg31m1(seed, threadSafe) :> System.Random - /// Creates a 32-bit combined multiple recursive generator with 2 components of order 3 pRNG with a custom seed based on uinque GUIDs - let mrg32k3a () = new Mrg32k3a() :> System.Random - let mrg32k3aSeed (seed:int) = new Mrg32k3a(seed) :> System.Random - let mrg32k3aWith seed threadSafe = new Mrg32k3a(seed, threadSafe) :> System.Random - let mrg32k3aSamples (seed:int) length = Mrg32k3a.Samples(length, seed) - let mrg32k3aSampleSeq (seed:int) = Mrg32k3a.SampleSequence(seed) + /// Creates a 32-bit combined multiple recursive generator with 2 components of order 3 pRNG with a robust seed + let inline mrg32k3a () = Mrg32k3a() :> System.Random + let inline mrg32k3aSeed (seed:int) = Mrg32k3a(seed) :> System.Random + let inline mrg32k3aWith (seed:int) threadSafe = Mrg32k3a(seed, threadSafe) :> System.Random diff --git a/src/Numerics/Random/CryptoRandomSource.cs b/src/Numerics/Random/CryptoRandomSource.cs index 8bc864b9..86389ee8 100644 --- a/src/Numerics/Random/CryptoRandomSource.cs +++ b/src/Numerics/Random/CryptoRandomSource.cs @@ -92,7 +92,7 @@ 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 DoSample() + protected override sealed double DoSample() { var bytes = new byte[4]; _crypto.GetBytes(bytes); @@ -109,7 +109,7 @@ namespace MathNet.Numerics.Random /// /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// - public static double[] Samples(int length) + public static double[] Doubles(int length) { var rnd = new RNGCryptoServiceProvider(); var bytes = new byte[length*4]; @@ -125,7 +125,7 @@ namespace MathNet.Numerics.Random /// /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// - public static IEnumerable SampleSequence() + public static IEnumerable DoubleSequence() { var rnd = new RNGCryptoServiceProvider(); var buffer = new byte[1024*4]; diff --git a/src/Numerics/Random/Mcg31m1.cs b/src/Numerics/Random/Mcg31m1.cs index d169672d..b363a74e 100644 --- a/src/Numerics/Random/Mcg31m1.cs +++ b/src/Numerics/Random/Mcg31m1.cs @@ -95,7 +95,7 @@ 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 DoSample() + protected override sealed double DoSample() { double ret = _xn*Reciprocal; _xn = (_xn*Multiplier)%Modulus; @@ -106,7 +106,7 @@ namespace MathNet.Numerics.Random /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static double[] Doubles(int length, int seed) { if (seed == 0) { @@ -127,7 +127,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { if (seed == 0) { diff --git a/src/Numerics/Random/Mcg59.cs b/src/Numerics/Random/Mcg59.cs index 5449be1b..f78eff5f 100644 --- a/src/Numerics/Random/Mcg59.cs +++ b/src/Numerics/Random/Mcg59.cs @@ -37,9 +37,9 @@ namespace MathNet.Numerics.Random /// public class Mcg59 : RandomSource { - const double Reciprocal = 1.0/Modulus; const ulong Modulus = 576460752303423488; const ulong Multiplier = 302875106592253; + const double Reciprocal = 1.0/Modulus; ulong _xn; /// @@ -97,7 +97,7 @@ 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 DoSample() + protected override sealed double DoSample() { double ret = _xn*Reciprocal; _xn = (_xn*Multiplier)%Modulus; @@ -108,7 +108,7 @@ namespace MathNet.Numerics.Random /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static double[] Doubles(int length, int seed) { if (seed == 0) { @@ -129,7 +129,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { if (seed == 0) { diff --git a/src/Numerics/Random/MersenneTwister.cs b/src/Numerics/Random/MersenneTwister.cs index 19457160..a26477b2 100644 --- a/src/Numerics/Random/MersenneTwister.cs +++ b/src/Numerics/Random/MersenneTwister.cs @@ -67,7 +67,12 @@ */ using System.Collections.Generic; + +#if PORTABLE +using System; +#else using System.Threading; +#endif namespace MathNet.Numerics.Random { @@ -316,7 +321,7 @@ 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 DoSample() + protected override sealed double DoSample() { return genrand_int32()*Reciprocal; } @@ -335,7 +340,7 @@ namespace MathNet.Numerics.Random /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static double[] Doubles(int length, int seed) { uint[] t = new uint[624]; int k; @@ -389,7 +394,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { uint[] t = new uint[624]; int k; diff --git a/src/Numerics/Random/Mrg32k3a.cs b/src/Numerics/Random/Mrg32k3a.cs index 8c682335..fa80cf77 100644 --- a/src/Numerics/Random/Mrg32k3a.cs +++ b/src/Numerics/Random/Mrg32k3a.cs @@ -110,7 +110,7 @@ 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 DoSample() + protected override sealed double DoSample() { double xn = A12*_xn2 - A13*_xn3; double k = (long)(xn/Modulus1); @@ -145,7 +145,7 @@ namespace MathNet.Numerics.Random /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static double[] Doubles(int length, int seed) { double x1 = 1; double x2 = 1; @@ -188,7 +188,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { double x1 = 1; double x2 = 1; diff --git a/src/Numerics/Random/Palf.cs b/src/Numerics/Random/Palf.cs index 40bed9c2..635d98f1 100644 --- a/src/Numerics/Random/Palf.cs +++ b/src/Numerics/Random/Palf.cs @@ -137,7 +137,7 @@ namespace MathNet.Numerics.Random LongLag = ((longLag/_threads) + 1)*_threads; } - _x = Generate.Map(MersenneTwister.Samples(LongLag, seed), uniform => (uint)(uniform*uint.MaxValue)); + _x = Generate.Map(MersenneTwister.Doubles(LongLag, seed), uniform => (uint)(uniform*uint.MaxValue)); _k = LongLag; } @@ -212,7 +212,7 @@ 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 DoSample() + protected override sealed double DoSample() { if (_k >= LongLag) { @@ -227,7 +227,7 @@ namespace MathNet.Numerics.Random /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static double[] Doubles(int length, int seed) { if (seed == 0) { @@ -244,7 +244,7 @@ namespace MathNet.Numerics.Random longLag = ((longLag/threads) + 1)*threads; } - var x = Generate.Map(MersenneTwister.Samples(longLag, seed), uniform => (uint)(uniform*uint.MaxValue)); + var x = Generate.Map(MersenneTwister.Doubles(longLag, seed), uniform => (uint)(uniform*uint.MaxValue)); var k = longLag; var data = new double[length]; @@ -277,7 +277,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { if (seed == 0) { @@ -294,7 +294,7 @@ namespace MathNet.Numerics.Random longLag = ((longLag/threads) + 1)*threads; } - var x = Generate.Map(MersenneTwister.Samples(longLag, seed), uniform => (uint)(uniform*uint.MaxValue)); + var x = Generate.Map(MersenneTwister.Doubles(longLag, seed), uniform => (uint)(uniform*uint.MaxValue)); var k = longLag; while (true) diff --git a/src/Numerics/Random/RandomExtensions.cs b/src/Numerics/Random/RandomExtensions.cs index 7d75253e..45398c01 100644 --- a/src/Numerics/Random/RandomExtensions.cs +++ b/src/Numerics/Random/RandomExtensions.cs @@ -29,27 +29,111 @@ // using System; +using System.Collections.Generic; 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 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 Nummerics or derived from the RandomSource class. + /// + public static void NextDoubles(this System.Random rnd, double[] values) + { + var rs = rnd as RandomSource; + if (rs != null) + { + 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 Nummerics 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 Nummerics or derived from the RandomSource class. + /// + public static IEnumerable NextDoubleSequence(this System.Random rnd) + { + var rs = rnd as RandomSource; + if (rs != null) + { + 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 Nummerics 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; + } + /// /// Returns a nonnegative random number less than . /// - /// - /// The random object to extend. - /// + /// 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 Nummerics or derived from the RandomSource class. + /// public static long NextInt64(this System.Random rnd) { var buffer = new byte[sizeof (long)]; @@ -68,14 +152,16 @@ namespace MathNet.Numerics.Random /// /// Returns a random number of the full Int32 range. /// - /// - /// The random object to extend. - /// + /// 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 Nummerics or derived from the RandomSource class. + /// public static int NextFullRangeInt32(this System.Random rnd) { var buffer = new byte[sizeof (int)]; @@ -86,14 +172,16 @@ namespace MathNet.Numerics.Random /// /// Returns a random number of the full Int64 range. /// - /// - /// The random object to extend. - /// + /// 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 Nummerics or derived from the RandomSource class. + /// public static long NextFullRangeInt64(this System.Random rnd) { var buffer = new byte[sizeof (long)]; @@ -104,13 +192,15 @@ namespace MathNet.Numerics.Random /// /// Returns a nonnegative decimal floating point random number less than 1.0. /// - /// - /// The random object to extend. - /// + /// 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 Nummerics or derived from the RandomSource class. + /// public static decimal NextDecimal(this System.Random rnd) { decimal candidate; diff --git a/src/Numerics/Random/RandomSource.cs b/src/Numerics/Random/RandomSource.cs index 24830e8d..3f614ac1 100644 --- a/src/Numerics/Random/RandomSource.cs +++ b/src/Numerics/Random/RandomSource.cs @@ -66,36 +66,28 @@ namespace MathNet.Numerics.Random } /// - /// Returns an array of uniform random numbers greater than or equal to 0.0 and less than 1.0. + /// Fills an array with uniform random numbers greater than or equal to 0.0 and less than 1.0. /// - /// The size of the array. - /// if n is not greater than 0. - public double[] NextDoubles(int n) + /// The array to fill with random values. + public void NextDoubles(double[] values) { - if (n < 1) - { - throw new ArgumentException(Resources.ArgumentMustBePositive); - } - - var ret = new double[n]; if (_threadSafe) { lock (_lock) { - for (var i = 0; i < ret.Length; i++) + for (var i = 0; i < values.Length; i++) { - ret[i] = DoSample(); + values[i] = DoSample(); } } } else { - for (var i = 0; i < ret.Length; i++) + for (var i = 0; i < values.Length; i++) { - ret[i] = DoSample(); + values[i] = DoSample(); } } - return ret; } /// @@ -108,9 +100,10 @@ namespace MathNet.Numerics.Random yield return NextDouble(); } + var buffer = new double[64]; while (true) { - var buffer = NextDoubles(64); + NextDoubles(buffer); for (int i = 0; i < buffer.Length; i++) { yield return buffer[i]; @@ -222,7 +215,7 @@ namespace MathNet.Numerics.Random /// 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 override double Sample() + protected override sealed double Sample() { if (_threadSafe) { diff --git a/src/Numerics/Random/SystemRandomSource.cs b/src/Numerics/Random/SystemRandomSource.cs index 4f80f336..fb9c9804 100644 --- a/src/Numerics/Random/SystemRandomSource.cs +++ b/src/Numerics/Random/SystemRandomSource.cs @@ -29,9 +29,15 @@ // using System.Collections.Generic; -using System.Threading; using MathNet.Numerics.Threading; +#if PORTABLE +using System; +#else +using System.Runtime; +using System.Threading; +#endif + namespace MathNet.Numerics.Random { /// @@ -111,31 +117,42 @@ 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 DoSample() + protected override sealed double DoSample() { return _random.NextDouble(); } /// - /// Returns an array of uniform random numbers greater than or equal to 0.0 and less than 1.0. + /// Fill an array with uniform random numbers greater than or equal to 0.0 and less than 1.0. /// /// Parallelized on large length, but also supports being called in parallel from multiple threads - public static double[] Samples(int length) + public static void Doubles(double[] values) { - if (length < 2048) + if (values.Length < 2048) { - return Default.NextDoubles(length); + Default.NextDoubles(values); + return; } - var data = new double[length]; - CommonParallel.For(0, length, length >= 65536 ? 8192 : length >= 16384 ? 2048 : 1024, (a, b) => + CommonParallel.For(0, values.Length, values.Length >= 65536 ? 8192 : values.Length >= 16384 ? 2048 : 1024, (a, b) => { var rnd = new System.Random(RandomSeed.Robust()); for (int i = a; i < b; i++) { - data[i] = rnd.NextDouble(); + values[i] = rnd.NextDouble(); } }); + } + + /// + /// Returns an array of uniform random numbers greater than or equal to 0.0 and less than 1.0. + /// + /// Parallelized on large length, but also supports being called in parallel from multiple threads + [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] + public static double[] Doubles(int length) + { + var data = new double[length]; + Doubles(data); return data; } @@ -143,7 +160,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of uniform random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence() + public static IEnumerable DoubleSequence() { var rnd1 = Default; for (int i = 0; i < 128; i++) @@ -159,18 +176,28 @@ namespace MathNet.Numerics.Random } /// - /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. + /// Fills an array with random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static void Doubles(double[] values, int seed) { var rnd = new System.Random(seed); - var data = new double[length]; - for (int i = 0; i < data.Length; i++) + for (int i = 0; i < values.Length; i++) { - data[i] = rnd.NextDouble(); + values[i] = rnd.NextDouble(); } + } + + /// + /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. + /// + /// Supports being called in parallel from multiple threads. + [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] + public static double[] Doubles(int length, int seed) + { + var data = new double[length]; + Doubles(data, seed); return data; } @@ -178,7 +205,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { var rnd = new System.Random(seed); diff --git a/src/Numerics/Random/WH1982.cs b/src/Numerics/Random/WH1982.cs index abcc74fe..d35bc3b8 100644 --- a/src/Numerics/Random/WH1982.cs +++ b/src/Numerics/Random/WH1982.cs @@ -105,7 +105,7 @@ 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 DoSample() + protected override sealed double DoSample() { _xn = (171*_xn)%Modx; _yn = (172*_yn)%Mody; @@ -120,7 +120,7 @@ namespace MathNet.Numerics.Random /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static double[] Doubles(int length, int seed) { if (seed == 0) { @@ -147,7 +147,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { if (seed == 0) { diff --git a/src/Numerics/Random/WH2006.cs b/src/Numerics/Random/WH2006.cs index 376e63c5..6cd0ad70 100644 --- a/src/Numerics/Random/WH2006.cs +++ b/src/Numerics/Random/WH2006.cs @@ -107,7 +107,7 @@ 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 DoSample() + protected override sealed double DoSample() { _xn = 11600*_xn%Modx; _yn = 47003*_yn%Mody; @@ -123,7 +123,7 @@ namespace MathNet.Numerics.Random /// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads. - public static double[] Samples(int length, int seed) + public static double[] Doubles(int length, int seed) { if (seed == 0) { @@ -152,7 +152,7 @@ namespace MathNet.Numerics.Random /// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0. /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. - public static IEnumerable SampleSequence(int seed) + public static IEnumerable DoubleSequence(int seed) { if (seed == 0) { diff --git a/src/Numerics/Random/Xorshift.cs b/src/Numerics/Random/Xorshift.cs index cf02bff1..46133ca0 100644 --- a/src/Numerics/Random/Xorshift.cs +++ b/src/Numerics/Random/Xorshift.cs @@ -253,7 +253,7 @@ 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 DoSample() + protected override sealed double DoSample() { var t = (_a*_x) + _c; _x = _y; @@ -268,7 +268,7 @@ namespace MathNet.Numerics.Random /// /// Supports being called in parallel from multiple threads. [CLSCompliant(false)] - public static double[] Samples(int length, int seed, ulong a = ASeed, ulong c = CSeed, ulong x1 = YSeed, ulong x2 = ZSeed) + public static double[] Doubles(int length, int seed, ulong a = ASeed, ulong c = CSeed, ulong x1 = YSeed, ulong x2 = ZSeed) { if (a <= c) { @@ -299,7 +299,7 @@ namespace MathNet.Numerics.Random /// /// Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each. [CLSCompliant(false)] - public static IEnumerable SampleSequence(int seed, ulong a = ASeed, ulong c = CSeed, ulong x1 = YSeed, ulong x2 = ZSeed) + public static IEnumerable DoubleSequence(int seed, ulong a = ASeed, ulong c = CSeed, ulong x1 = YSeed, ulong x2 = ZSeed) { if (a <= c) { diff --git a/src/UnitTests/Random/Mcg31m1Tests.cs b/src/UnitTests/Random/Mcg31m1Tests.cs index 9302d041..27782bdb 100644 --- a/src/UnitTests/Random/Mcg31m1Tests.cs +++ b/src/UnitTests/Random/Mcg31m1Tests.cs @@ -49,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(Mcg31m1.Samples(1000, 1), Is.EqualTo(new Mcg31m1(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(Mcg31m1.Doubles(1000, 1), Is.EqualTo(new Mcg31m1(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/Mcg59Tests.cs b/src/UnitTests/Random/Mcg59Tests.cs index 703958c4..dc433270 100644 --- a/src/UnitTests/Random/Mcg59Tests.cs +++ b/src/UnitTests/Random/Mcg59Tests.cs @@ -49,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(Mcg59.Samples(1000, 1), Is.EqualTo(new Mcg59(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(Mcg59.Doubles(1000, 1), Is.EqualTo(new Mcg59(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/MersenneTwisterTests.cs b/src/UnitTests/Random/MersenneTwisterTests.cs index 4847df84..1a41bd07 100644 --- a/src/UnitTests/Random/MersenneTwisterTests.cs +++ b/src/UnitTests/Random/MersenneTwisterTests.cs @@ -62,7 +62,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(MersenneTwister.Samples(1000, 1), Is.EqualTo(new MersenneTwister(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(MersenneTwister.Doubles(1000, 1), Is.EqualTo(new MersenneTwister(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/Mrg32k3aTests.cs b/src/UnitTests/Random/Mrg32k3aTests.cs index 0ec26f19..5e6580b4 100644 --- a/src/UnitTests/Random/Mrg32k3aTests.cs +++ b/src/UnitTests/Random/Mrg32k3aTests.cs @@ -49,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(Mrg32k3a.Samples(1000, 1), Is.EqualTo(new Mrg32k3a(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(Mrg32k3a.Doubles(1000, 1), Is.EqualTo(new Mrg32k3a(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/PalfTests.cs b/src/UnitTests/Random/PalfTests.cs index 2f8b9b0b..bf0147d1 100644 --- a/src/UnitTests/Random/PalfTests.cs +++ b/src/UnitTests/Random/PalfTests.cs @@ -68,7 +68,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(Palf.Samples(1000, 1), Is.EqualTo(new Palf(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(Palf.Doubles(1000, 1), Is.EqualTo(new Palf(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/SystemRandomSourceTests.cs b/src/UnitTests/Random/SystemRandomSourceTests.cs index f0ca3ee5..009560bb 100644 --- a/src/UnitTests/Random/SystemRandomSourceTests.cs +++ b/src/UnitTests/Random/SystemRandomSourceTests.cs @@ -46,7 +46,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(SystemRandomSource.Samples(1000, 1), Is.EqualTo(new SystemRandomSource(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(SystemRandomSource.Doubles(1000, 1), Is.EqualTo(new SystemRandomSource(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/WH1982Tests.cs b/src/UnitTests/Random/WH1982Tests.cs index d65537e1..a68321c4 100644 --- a/src/UnitTests/Random/WH1982Tests.cs +++ b/src/UnitTests/Random/WH1982Tests.cs @@ -49,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(WH1982.Samples(1000, 1), Is.EqualTo(new WH1982(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(WH1982.Doubles(1000, 1), Is.EqualTo(new WH1982(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/WH2006Tests.cs b/src/UnitTests/Random/WH2006Tests.cs index 6c91d20a..6e40f506 100644 --- a/src/UnitTests/Random/WH2006Tests.cs +++ b/src/UnitTests/Random/WH2006Tests.cs @@ -49,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(WH2006.Samples(1000, 1), Is.EqualTo(new WH2006(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(WH2006.Doubles(1000, 1), Is.EqualTo(new WH2006(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } } diff --git a/src/UnitTests/Random/XorshiftTests.cs b/src/UnitTests/Random/XorshiftTests.cs index ed220177..c4a9ae95 100644 --- a/src/UnitTests/Random/XorshiftTests.cs +++ b/src/UnitTests/Random/XorshiftTests.cs @@ -49,7 +49,7 @@ namespace MathNet.Numerics.UnitTests.Random [Test] public void StaticSamplesConsistent() { - Assert.That(Xorshift.Samples(1000, 1), Is.EqualTo(new Xorshift(1).NextDoubles(1000)).Within(1e-12).AsCollection); + Assert.That(Xorshift.Doubles(1000, 1), Is.EqualTo(new Xorshift(1).NextDoubles(1000)).Within(1e-12).AsCollection); } } }