diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj
index f19b464f..0063697a 100644
--- a/src/Numerics/Numerics.csproj
+++ b/src/Numerics/Numerics.csproj
@@ -167,6 +167,11 @@
+
+ True
+ True
+ Resources.resx
+
@@ -428,11 +433,6 @@
-
- True
- True
- Resources.resx
-
@@ -472,8 +472,8 @@
PublicResXFileCodeGenerator
- Resources.Designer.cs
Designer
+ Resources.Designer.cs
diff --git a/src/Numerics/Properties/Resources.Designer.cs b/src/Numerics/Properties/Resources.Designer.cs
index b4650370..ca56ef13 100644
--- a/src/Numerics/Properties/Resources.Designer.cs
+++ b/src/Numerics/Properties/Resources.Designer.cs
@@ -314,6 +314,15 @@ namespace MathNet.Numerics.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to In the specified range, the exclusive maximum must be greater than the inclusive minimum..
+ ///
+ public static string ArgumentMaxExclusiveMustBeLargerThanMinInclusive {
+ get {
+ return ResourceManager.GetString("ArgumentMaxExclusiveMustBeLargerThanMinInclusive", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to In the specified range, the minimum is greater than maximum..
///
diff --git a/src/Numerics/Properties/Resources.resx b/src/Numerics/Properties/Resources.resx
index e3c53791..13cc7a6e 100644
--- a/src/Numerics/Properties/Resources.resx
+++ b/src/Numerics/Properties/Resources.resx
@@ -1,17 +1,17 @@
-
@@ -282,6 +282,9 @@
In the specified range, the minimum is greater than maximum.
+
+ In the specified range, the exclusive maximum must be greater than the inclusive minimum.
+
The upper bound must be at least as large as the lower bound.
diff --git a/src/Numerics/Random/RandomSource.cs b/src/Numerics/Random/RandomSource.cs
index a3ca0deb..cce5a1f8 100644
--- a/src/Numerics/Random/RandomSource.cs
+++ b/src/Numerics/Random/RandomSource.cs
@@ -3,7 +3,7 @@
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
-// Copyright (c) 2009-2015 Math.NET
+// Copyright (c) 2009-2016 Math.NET
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
@@ -133,28 +133,39 @@ namespace MathNet.Numerics.Random
return DoSampleInteger();
}
}
-
- return DoSampleInteger();
+ else
+ {
+ return DoSampleInteger();
+ }
}
///
/// Returns a random number less then a specified maximum.
///
- /// The exclusive upper bound of the random number returned.
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 1.
/// A 32-bit signed integer less than .
- /// is negative.
+ /// is zero or negative.
public sealed override int Next(int maxExclusive)
{
+ // Invalid case: Zero and less are not valid use cases.
if (maxExclusive <= 0)
{
throw new ArgumentException(Resources.ArgumentMustBePositive);
}
+ // Fast case: Only zero is allowed to be returned. No sampling is needed.
+ if (maxExclusive == 1)
+ {
+ return 0;
+ }
+
+ // Simple case: standard range
if (maxExclusive == int.MaxValue)
{
return Next();
}
+ // Sample with maxExclusive ≥ 2
if (_threadSafe)
{
lock (_lock)
@@ -162,28 +173,39 @@ namespace MathNet.Numerics.Random
return DoSampleInteger(maxExclusive);
}
}
-
- return DoSampleInteger(maxExclusive);
+ else
+ {
+ return DoSampleInteger(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 .
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.
///
/// 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)
+ // Invalid case: empty range.
+ if (minInclusive >= maxExclusive)
{
- throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue);
+ throw new ArgumentException(Resources.ArgumentMaxExclusiveMustBeLargerThanMinInclusive);
}
+ // Fast case: Only minInclusive is allowed to be returned. No sampling is needed.
+ if (maxExclusive == minInclusive + 1)
+ {
+ return minInclusive;
+ }
+
+ // Simple case: simple range
if (minInclusive == 0)
{
+ // Simple case: standard range
if (maxExclusive == int.MaxValue)
{
return Next();
@@ -192,6 +214,7 @@ namespace MathNet.Numerics.Random
return Next(maxExclusive);
}
+ // Sample with maxExclusive ≥ minExclusive + 2
if (_threadSafe)
{
lock (_lock)
@@ -199,8 +222,10 @@ namespace MathNet.Numerics.Random
return DoSampleInteger(minInclusive, maxExclusive);
}
}
-
- return DoSampleInteger(minInclusive, maxExclusive);
+ else
+ {
+ return DoSampleInteger(minInclusive, maxExclusive);
+ }
}
///
@@ -243,15 +268,30 @@ namespace MathNet.Numerics.Random
/// 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.
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 1.
public void NextInt32s(int[] values, int maxExclusive)
{
+ // Invalid case: Zero and less are not valid use cases.
+ if (maxExclusive <= 0)
+ {
+ throw new ArgumentException(Resources.ArgumentMustBePositive);
+ }
+
+ // Fast case: Only zero is allowed to be returned. No sampling is needed.
+ if (maxExclusive == 1)
+ {
+ Array.Clear(values, 0, values.Length);
+ return;
+ }
+
+ // Simple case: standard range
if (maxExclusive == int.MaxValue)
{
NextInt32s(values);
return;
}
+ // Sample with maxExclusive ≥ 2
if (_threadSafe)
{
lock (_lock)
@@ -271,27 +311,46 @@ namespace MathNet.Numerics.Random
}
}
+ ///
+ /// Returns an array with random 32-bit signed integers within the specified range.
+ ///
+ /// The size of the array to fill.
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 1.
+ public int[] NextInt32s(int count, int maxExclusive)
+ {
+ var values = new int[count];
+ NextInt32s(values, maxExclusive);
+ 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 .
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.
public void NextInt32s(int[] values, int minInclusive, int maxExclusive)
{
- if (minInclusive > maxExclusive)
+ // Invalid case: empty range.
+ if (minInclusive >= maxExclusive)
{
- throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue);
+ throw new ArgumentException(Resources.ArgumentMaxExclusiveMustBeLargerThanMinInclusive);
}
- if (maxExclusive == int.MaxValue && minInclusive == 0)
+ // Fast case: Only minInclusive is allowed to be returned. No sampling is needed.
+ if (maxExclusive == minInclusive + 1)
{
- NextInt32s(values);
+ for (var i = 0; i < values.Length; i++)
+ {
+ values[i] = minInclusive;
+ }
return;
}
+ // Simple case: simple range
if (minInclusive == 0)
{
+ // Simple case: standard range
if (maxExclusive == int.MaxValue)
{
NextInt32s(values);
@@ -302,6 +361,7 @@ namespace MathNet.Numerics.Random
return;
}
+ // Sample with maxExclusive ≥ minExclusive + 2
if (_threadSafe)
{
lock (_lock)
@@ -326,7 +386,7 @@ namespace MathNet.Numerics.Random
///
/// 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 .
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.
public int[] NextInt32s(int count, int minInclusive, int maxExclusive)
{
var values = new int[count];
@@ -359,7 +419,7 @@ namespace MathNet.Numerics.Random
/// 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 .
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive > minExclusive.
public IEnumerable NextInt32Sequence(int minInclusive, int maxExclusive)
{
if (minInclusive > maxExclusive)
@@ -455,6 +515,13 @@ namespace MathNet.Numerics.Random
///
protected virtual int DoSampleInt32WithNBits(int bitCount)
{
+ // Fast case: Only 0 is allowed to be returned
+ // No random call is needed
+ if (bitCount == 0)
+ {
+ return 0;
+ }
+
var bytes = new byte[4];
DoSampleBytes(bytes);
@@ -472,6 +539,13 @@ namespace MathNet.Numerics.Random
///
protected virtual long DoSampleInt64WithNBits(int bitCount)
{
+ // Fast case: Only 0 is allowed to be returned
+ // No random call is needed
+ if (bitCount == 0)
+ {
+ return 0;
+ }
+
var bytes = new byte[8];
DoSampleBytes(bytes);
@@ -486,7 +560,7 @@ namespace MathNet.Numerics.Random
///
/// Returns a random 32-bit signed integer within the specified range.
///
- /// The exclusive upper bound of the random number returned.
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 2 (not verified, must be ensured by caller).
protected virtual int DoSampleInteger(int maxExclusive)
{
// non-biased implementation
@@ -516,9 +590,10 @@ namespace MathNet.Numerics.Random
/// 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 .
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive ≥ minExclusive + 2 (not verified, must be ensured by caller).
protected virtual int DoSampleInteger(int minInclusive, int maxExclusive)
{
+ // Sample with maxExclusive ≥ 2
return DoSampleInteger(maxExclusive - minInclusive) + minInclusive;
}
}
diff --git a/src/Numerics/Random/SystemRandomSource.cs b/src/Numerics/Random/SystemRandomSource.cs
index 04c0dee0..e7554c3c 100644
--- a/src/Numerics/Random/SystemRandomSource.cs
+++ b/src/Numerics/Random/SystemRandomSource.cs
@@ -126,6 +126,10 @@ namespace MathNet.Numerics.Random
return _random.Next();
}
+ ///
+ /// Returns a random 32-bit signed integer within the specified range.
+ ///
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive ≥ 2 (not verified, must be ensured by caller).
protected override int DoSampleInteger(int maxExclusive)
{
return _random.Next(maxExclusive);
@@ -135,12 +139,15 @@ namespace MathNet.Numerics.Random
/// 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 .
+ /// The exclusive upper bound of the random number returned. Range: maxExclusive ≥ minExclusive + 2 (not verified, must be ensured by caller).
protected override int DoSampleInteger(int minInclusive, int maxExclusive)
{
return _random.Next(minInclusive, maxExclusive);
}
+ ///
+ /// Fills the elements of a specified array of bytes with random numbers in full range, including zero and 255 ().
+ ///
protected override void DoSampleBytes(byte[] buffer)
{
_random.NextBytes(buffer);
diff --git a/src/UnitTests/Random/RandomTests.cs b/src/UnitTests/Random/RandomTests.cs
index 408ff02d..2e1d5ab5 100644
--- a/src/UnitTests/Random/RandomTests.cs
+++ b/src/UnitTests/Random/RandomTests.cs
@@ -78,6 +78,29 @@ namespace MathNet.Numerics.UnitTests.Random
Assert.IsTrue(sum >= (N/2.0) - (.05*N));
Assert.IsTrue(sum <= (N/2.0) + (.05*N));
+ var disposable = random as IDisposable;
+ if (disposable != null)
+ {
+ disposable.Dispose();
+ }
+ }
+
+ ///
+ /// Next() result is in boundaries.
+ ///
+ [Test]
+ public void Boundaries()
+ {
+ var random = (System.Random)Activator.CreateInstance(_randomType, new object[] { false });
+
+ for (var i = 1; i < N; i++)
+ {
+ var j = N;
+ var next = random.Next(i, j);
+ Assert.IsTrue(next >= i, string.Format("Value {0} is smaller than lower bound {1}", next, i));
+ Assert.IsTrue(next < j, string.Format("Value {0} is larger or equal to upper bound {1}", next, j));
+ }
+
var disposable = random as IDisposable;
if (disposable != null)
{