From 484f1e44f2bdf2661505177a53e8489a565125b6 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Thu, 18 Aug 2016 14:20:48 +0200 Subject: [PATCH] Random: improved fallbacks on zero-minInclusive integer sampling --- src/Numerics/Random/CryptoRandomSource.cs | 2 +- src/Numerics/Random/RandomSource.cs | 86 +++++++++++++++++++---- src/Numerics/Random/SystemRandomSource.cs | 5 ++ 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/src/Numerics/Random/CryptoRandomSource.cs b/src/Numerics/Random/CryptoRandomSource.cs index 0f068ac8..c25e3b8f 100644 --- a/src/Numerics/Random/CryptoRandomSource.cs +++ b/src/Numerics/Random/CryptoRandomSource.cs @@ -110,7 +110,7 @@ namespace MathNet.Numerics.Random var bytes = new byte[4]; _crypto.GetBytes(bytes); uint uint32 = BitConverter.ToUInt32(bytes, 0); - int int31 = (int)uint32 >> 1; + int int31 = (int)(uint32 >> 1); if (int31 == int.MaxValue) { return DoSampleInteger(); diff --git a/src/Numerics/Random/RandomSource.cs b/src/Numerics/Random/RandomSource.cs index a1648748..b0002ddb 100644 --- a/src/Numerics/Random/RandomSource.cs +++ b/src/Numerics/Random/RandomSource.cs @@ -159,11 +159,11 @@ namespace MathNet.Numerics.Random { lock (_lock) { - return DoSampleInteger(0, maxExclusive); + return DoSampleInteger(maxExclusive); } } - return DoSampleInteger(0, maxExclusive); + return DoSampleInteger(maxExclusive); } /// @@ -182,9 +182,14 @@ namespace MathNet.Numerics.Random throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); } - if (maxExclusive == int.MaxValue && minInclusive == 0) + if (minInclusive == 0) { - return Next(); + if (maxExclusive == int.MaxValue) + { + return Next(); + } + + return Next(maxExclusive); } if (_threadSafe) @@ -234,6 +239,38 @@ namespace MathNet.Numerics.Random return values; } + /// + /// Fills an array with random numbers within a specified range. + /// + /// The array to fill with random values. + /// The exclusive upper bound of the random number returned. + public void NextInt32s(int[] values, int maxExclusive) + { + if (maxExclusive == int.MaxValue) + { + NextInt32s(values); + return; + } + + if (_threadSafe) + { + lock (_lock) + { + for (var i = 0; i < values.Length; i++) + { + values[i] = DoSampleInteger(maxExclusive); + } + } + } + else + { + for (var i = 0; i < values.Length; i++) + { + values[i] = DoSampleInteger(maxExclusive); + } + } + } + /// /// Fills an array with random numbers within a specified range. /// @@ -253,6 +290,18 @@ namespace MathNet.Numerics.Random return; } + if (minInclusive == 0) + { + if (maxExclusive == int.MaxValue) + { + NextInt32s(values); + return; + } + + NextInt32s(values, maxExclusive); + return; + } + if (_threadSafe) { lock (_lock) @@ -389,16 +438,6 @@ namespace MathNet.Numerics.Random 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 (). /// @@ -409,5 +448,24 @@ namespace MathNet.Numerics.Random buffer[i] = (byte)(DoSampleInteger() % 256); } } + + /// + /// Returns a random 32-bit signed integer within the specified range. + /// + /// The exclusive upper bound of the random number returned. + protected virtual int DoSampleInteger(int maxExclusive) + { + return (int)(DoSample() * maxExclusive); + } + + /// + /// 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 DoSampleInteger(maxExclusive - minInclusive) + minInclusive; + } } } diff --git a/src/Numerics/Random/SystemRandomSource.cs b/src/Numerics/Random/SystemRandomSource.cs index 272f3c07..04c0dee0 100644 --- a/src/Numerics/Random/SystemRandomSource.cs +++ b/src/Numerics/Random/SystemRandomSource.cs @@ -126,6 +126,11 @@ namespace MathNet.Numerics.Random return _random.Next(); } + protected override int DoSampleInteger(int maxExclusive) + { + return _random.Next(maxExclusive); + } + /// /// Returns a random 32-bit signed integer within the specified range. ///