Browse Source

Random: RandomSource.DoSampleInteger for direct integer sampling without floating points #359

MersenneTwister integer sampling now matches standard implementation.
netstandard
Christoph Ruegg 11 years ago
parent
commit
b209ed9d58
  1. 24
      src/Numerics/Random/CryptoRandomSource.cs
  2. 7
      src/Numerics/Random/Mcg31m1.cs
  3. 7
      src/Numerics/Random/Mcg59.cs
  4. 44
      src/Numerics/Random/MersenneTwister.cs
  5. 7
      src/Numerics/Random/Mrg32k3a.cs
  6. 36
      src/Numerics/Random/Palf.cs
  7. 6
      src/Numerics/Random/RandomExtensions.cs
  8. 84
      src/Numerics/Random/RandomSource.cs
  9. 25
      src/Numerics/Random/SystemRandomSource.cs
  10. 9
      src/Numerics/Random/WH1982.cs
  11. 7
      src/Numerics/Random/WH2006.cs
  12. 29
      src/Numerics/Random/Xorshift.cs
  13. 12
      src/UnitTests/Random/MersenneTwisterTests.cs

24
src/Numerics/Random/CryptoRandomSource.cs

@ -86,18 +86,32 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
var bytes = new byte[4]; var bytes = new byte[4];
_crypto.GetBytes(bytes); _crypto.GetBytes(bytes);
return BitConverter.ToUInt32(bytes, 0)*Reciprocal; return BitConverter.ToUInt32(bytes, 0)*Reciprocal;
} }
/// <summary>
/// Returns a random 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>
/// </summary>
protected sealed override int DoSampleInteger()
{
var bytes = new byte[4];
_crypto.GetBytes(bytes);
uint uint32 = BitConverter.ToUInt32(bytes, 0);
int int31 = (int)uint32 >> 1;
if (int31 == int.MaxValue)
{
return DoSampleInteger();
}
return int31;
}
public void Dispose() public void Dispose()
{ {
#if !NET35 #if !NET35

7
src/Numerics/Random/Mcg31m1.cs

@ -96,12 +96,9 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
double ret = _xn*Reciprocal; double ret = _xn*Reciprocal;
_xn = (_xn*Multiplier)%Modulus; _xn = (_xn*Multiplier)%Modulus;

7
src/Numerics/Random/Mcg59.cs

@ -97,12 +97,9 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
double ret = _xn*Reciprocal; double ret = _xn*Reciprocal;
_xn = (_xn*Multiplier)%Modulus; _xn = (_xn*Multiplier)%Modulus;

44
src/Numerics/Random/MersenneTwister.cs

@ -28,10 +28,10 @@
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
// </copyright> // </copyright>
/* /*
Original code's copyright and license: Original code's copyright and license:
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
@ -44,8 +44,8 @@
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote 3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written products derived from this software without specific prior written
permission. permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@ -105,7 +105,7 @@ namespace MathNet.Numerics.Random
/// <summary> /// <summary>
/// Mersenne twister constant. /// Mersenne twister constant.
/// </summary> /// </summary>
const double Reciprocal = 1.0/4294967296.0; const double Reciprocal = 1.0/4294967296.0; // 1.0/(uint.MaxValue + 1.0)
/// <summary> /// <summary>
/// Mersenne twister constant. /// Mersenne twister constant.
@ -152,7 +152,7 @@ namespace MathNet.Numerics.Random
/// </summary> /// </summary>
/// <param name="seed">The seed value.</param> /// <param name="seed">The seed value.</param>
/// <remarks>Uses the value of <see cref="Control.ThreadSafeRandomNumberGenerators"/> to /// <remarks>Uses the value of <see cref="Control.ThreadSafeRandomNumberGenerators"/> to
/// set whether the instance is thread safe.</remarks> /// set whether the instance is thread safe.</remarks>
public MersenneTwister(int seed) public MersenneTwister(int seed)
{ {
init_genrand((uint)seed); init_genrand((uint)seed);
@ -246,8 +246,8 @@ namespace MathNet.Numerics.Random
uint k = (_n > key_length ? _n : key_length); uint k = (_n > key_length ? _n : key_length);
for (; k > 0; k--) for (; k > 0; k--)
{ {
_mt[i] = (_mt[i] ^ ((_mt[i - 1] ^ (_mt[i - 1] >> 30))*1664525)) + init_key[j] + j; //non linear _mt[i] = (_mt[i] ^ ((_mt[i - 1] ^ (_mt[i - 1] >> 30))*1664525)) + init_key[j] + j; //non linear
_mt[i] &= 0xffffffff; // for WORDSIZE > 32 machines _mt[i] &= 0xffffffff; // for WORDSIZE > 32 machines
i++; i++;
j++; j++;
if (i >= _n) if (i >= _n)
@ -259,8 +259,8 @@ namespace MathNet.Numerics.Random
} }
for (k = _n - 1; k > 0; k--) for (k = _n - 1; k > 0; k--)
{ {
_mt[i] = (_mt[i] ^ ((_mt[i - 1] ^ (_mt[i - 1] >> 30))*1566083941)) - i; // non linear _mt[i] = (_mt[i] ^ ((_mt[i - 1] ^ (_mt[i - 1] >> 30))*1566083941)) - i; // non linear
_mt[i] &= 0xffffffff; // for WORDSIZE > 32 machines _mt[i] &= 0xffffffff; // for WORDSIZE > 32 machines
i++; i++;
if (i >= _n) if (i >= _n)
{ {
@ -269,7 +269,7 @@ namespace MathNet.Numerics.Random
} }
} }
_mt[0] = 0x80000000; // MSB is 1; assuring non-zero initial array _mt[0] = 0x80000000; // MSB is 1; assuring non-zero initial array
}*/ }*/
/* generates a random number on [0,0xffffffff]-interval */ /* generates a random number on [0,0xffffffff]-interval */
@ -320,16 +320,28 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
return genrand_int32()*Reciprocal; return genrand_int32()*Reciprocal;
} }
/// <summary>
/// Returns a random 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>
/// </summary>
protected sealed override int DoSampleInteger()
{
uint uint32 = genrand_int32();
int int31 = (int)(uint32 >> 1);
if (int31 == int.MaxValue)
{
return DoSampleInteger();
}
return int31;
}
/* /// <summary> /* /// <summary>
/// Generates a random number on [0,1) with 53-bit resolution. /// Generates a random number on [0,1) with 53-bit resolution.
/// </summary> /// </summary>

7
src/Numerics/Random/Mrg32k3a.cs

@ -110,12 +110,9 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
double xn = A12*_xn2 - A13*_xn3; double xn = A12*_xn2 - A13*_xn3;
double k = (long)(xn/Modulus1); double k = (long)(xn/Modulus1);

36
src/Numerics/Random/Palf.cs

@ -62,7 +62,7 @@ namespace MathNet.Numerics.Random
/// <summary> /// <summary>
/// The multiplier to compute a double-precision floating point number [0, 1) /// The multiplier to compute a double-precision floating point number [0, 1)
/// </summary> /// </summary>
const double IntToDoubleMultiplier = 1.0/(int.MaxValue + 1.0); const double Reciprocal = 1.0/4294967296.0; // 1.0/(uint.MaxValue + 1.0)
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Palf"/> class using /// Initializes a new instance of the <see cref="Palf"/> class using
@ -211,20 +211,36 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
if (_k >= LongLag) if (_k >= LongLag)
{ {
Fill(); Fill();
} }
var x = _x[_k++]; return _x[_k++] * Reciprocal;
return (int)(x >> 1)*IntToDoubleMultiplier; }
/// <summary>
/// Returns a random 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>
/// </summary>
protected override int DoSampleInteger()
{
if (_k >= LongLag)
{
Fill();
}
uint uint32 = _x[_k++];
int int31 = (int)(uint32 >> 1);
if (int31 == int.MaxValue)
{
return DoSampleInteger();
}
return int31;
} }
/// <summary> /// <summary>
@ -272,7 +288,7 @@ namespace MathNet.Numerics.Random
k = 0; k = 0;
} }
values[i] = (int)(x[k++] >> 1)*IntToDoubleMultiplier; values[i] = x[k++]*Reciprocal;
} }
} }
@ -333,7 +349,7 @@ namespace MathNet.Numerics.Random
k = 0; k = 0;
} }
yield return (int)(x[k++] >> 1)*IntToDoubleMultiplier; yield return x[k++]*Reciprocal;
} }
} }
} }

6
src/Numerics/Random/RandomExtensions.cs

@ -188,7 +188,7 @@ namespace MathNet.Numerics.Random
/// </remarks> /// </remarks>
public static long NextInt64(this System.Random rnd) public static long NextInt64(this System.Random rnd)
{ {
var buffer = new byte[sizeof (long)]; var buffer = new byte[8];
rnd.NextBytes(buffer); rnd.NextBytes(buffer);
var candidate = BitConverter.ToInt64(buffer, 0); var candidate = BitConverter.ToInt64(buffer, 0);
@ -216,7 +216,7 @@ namespace MathNet.Numerics.Random
/// </remarks> /// </remarks>
public static int NextFullRangeInt32(this System.Random rnd) public static int NextFullRangeInt32(this System.Random rnd)
{ {
var buffer = new byte[sizeof (int)]; var buffer = new byte[4];
rnd.NextBytes(buffer); rnd.NextBytes(buffer);
return BitConverter.ToInt32(buffer, 0); return BitConverter.ToInt32(buffer, 0);
} }
@ -236,7 +236,7 @@ namespace MathNet.Numerics.Random
/// </remarks> /// </remarks>
public static long NextFullRangeInt64(this System.Random rnd) public static long NextFullRangeInt64(this System.Random rnd)
{ {
var buffer = new byte[sizeof (long)]; var buffer = new byte[8];
rnd.NextBytes(buffer); rnd.NextBytes(buffer);
return BitConverter.ToInt64(buffer, 0); return BitConverter.ToInt64(buffer, 0);
} }

84
src/Numerics/Random/RandomSource.cs

@ -4,7 +4,7 @@
// http://github.com/mathnet/mathnet-numerics // http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com // http://mathnetnumerics.codeplex.com
// //
// Copyright (c) 2009-2013 Math.NET // Copyright (c) 2009-2015 Math.NET
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
@ -117,17 +117,17 @@ namespace MathNet.Numerics.Random
/// <returns> /// <returns>
/// A 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>. /// A 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>.
/// </returns> /// </returns>
public override sealed int Next() public sealed override int Next()
{ {
if (_threadSafe) if (_threadSafe)
{ {
lock (_lock) lock (_lock)
{ {
return (int)(DoSample()*int.MaxValue); return DoSampleInteger();
} }
} }
return (int)(DoSample()*int.MaxValue); return DoSampleInteger();
} }
/// <summary> /// <summary>
@ -136,36 +136,41 @@ namespace MathNet.Numerics.Random
/// <param name="maxValue">The exclusive upper bound of the random number returned.</param> /// <param name="maxValue">The exclusive upper bound of the random number returned.</param>
/// <returns>A 32-bit signed integer less than <paramref name="maxValue"/>.</returns> /// <returns>A 32-bit signed integer less than <paramref name="maxValue"/>.</returns>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maxValue"/> is negative. </exception> /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maxValue"/> is negative. </exception>
public override sealed int Next(int maxValue) public sealed override int Next(int maxValue)
{ {
if (maxValue <= 0) if (maxValue <= 0)
{ {
throw new ArgumentException(Resources.ArgumentMustBePositive); throw new ArgumentException(Resources.ArgumentMustBePositive);
} }
if (maxValue == int.MaxValue)
{
return Next();
}
if (_threadSafe) if (_threadSafe)
{ {
lock (_lock) lock (_lock)
{ {
return (int)(DoSample()*maxValue); return DoSampleInteger(0, maxValue);
} }
} }
return (int)(DoSample()*maxValue); return DoSampleInteger(0, maxValue);
} }
/// <summary> /// <summary>
/// Returns a random number within a specified range. /// Returns a random number within a specified range.
/// </summary> /// </summary>
/// <param name="minValue">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param>
/// <returns> /// <returns>
/// A 32-bit signed integer greater than or equal to <paramref name="minValue"/> and less than <paramref name="maxValue"/>; that is, the range of return values includes <paramref name="minValue"/> but not <paramref name="maxValue"/>. If <paramref name="minValue"/> equals <paramref name="maxValue"/>, <paramref name="minValue"/> is returned. /// A 32-bit signed integer greater than or equal to <paramref name="minInclusive"/> and less than <paramref name="maxExclusive"/>; that is, the range of return values includes <paramref name="minInclusive"/> but not <paramref name="maxExclusive"/>. If <paramref name="minInclusive"/> equals <paramref name="maxExclusive"/>, <paramref name="minInclusive"/> is returned.
/// </returns> /// </returns>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>. </exception> /// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minInclusive"/> is greater than <paramref name="maxExclusive"/>. </exception>
public override sealed int Next(int minValue, int maxValue) public sealed override int Next(int minInclusive, int maxExclusive)
{ {
if (minValue > maxValue) if (minInclusive > maxExclusive)
{ {
throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue); throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue);
} }
@ -174,20 +179,20 @@ namespace MathNet.Numerics.Random
{ {
lock (_lock) lock (_lock)
{ {
return (int)(DoSample()*(maxValue - minValue)) + minValue; return DoSampleInteger(minInclusive, maxExclusive);
} }
} }
return (int)(DoSample()*(maxValue - minValue)) + minValue; return DoSampleInteger(minInclusive, maxExclusive);
} }
/// <summary> /// <summary>
/// Fills an array with random numbers within a specified range. /// Fills an array with random numbers within a specified range.
/// </summary> /// </summary>
/// <param name="values">The array to fill with random values.</param> /// <param name="values">The array to fill with random values.</param>
/// <param name="minValue">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param>
public void NextInt32s(int[] values, int minValue, int maxValue) public void NextInt32s(int[] values, int minInclusive, int maxExclusive)
{ {
if (_threadSafe) if (_threadSafe)
{ {
@ -195,7 +200,7 @@ namespace MathNet.Numerics.Random
{ {
for (var i = 0; i < values.Length; i++) for (var i = 0; i < values.Length; i++)
{ {
values[i] = (int)(DoSample()*(maxValue - minValue)) + minValue; values[i] = DoSampleInteger(minInclusive, maxExclusive);
} }
} }
} }
@ -203,7 +208,7 @@ namespace MathNet.Numerics.Random
{ {
for (var i = 0; i < values.Length; i++) for (var i = 0; i < values.Length; i++)
{ {
values[i] = (int)(DoSample()*(maxValue - minValue)) + minValue; values[i] = DoSampleInteger(minInclusive, maxExclusive);
} }
} }
} }
@ -211,19 +216,19 @@ namespace MathNet.Numerics.Random
/// <summary> /// <summary>
/// Returns an infinite sequence of random numbers within a specified range. /// Returns an infinite sequence of random numbers within a specified range.
/// </summary> /// </summary>
/// <param name="minValue">The inclusive lower bound of the random number returned.</param> /// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param> /// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param>
public IEnumerable<int> NextInt32Sequence(int minValue, int maxValue) public IEnumerable<int> NextInt32Sequence(int minInclusive, int maxExclusive)
{ {
for (int i = 0; i < 64; i++) for (int i = 0; i < 64; i++)
{ {
yield return Next(minValue, maxValue); yield return Next(minInclusive, maxExclusive);
} }
var buffer = new int[64]; var buffer = new int[64];
while (true) while (true)
{ {
NextInt32s(buffer, minValue, maxValue); NextInt32s(buffer, minInclusive, maxExclusive);
for (int i = 0; i < buffer.Length; i++) for (int i = 0; i < buffer.Length; i++)
{ {
yield return buffer[i]; yield return buffer[i];
@ -249,7 +254,7 @@ namespace MathNet.Numerics.Random
{ {
for (var i = 0; i < buffer.Length; i++) for (var i = 0; i < buffer.Length; i++)
{ {
buffer[i] = (byte)(((int)(DoSample()*int.MaxValue))%256); buffer[i] = (byte)(DoSampleInteger()%256);
} }
} }
@ -258,7 +263,7 @@ namespace MathNet.Numerics.Random
for (var i = 0; i < buffer.Length; i++) for (var i = 0; i < buffer.Length; i++)
{ {
buffer[i] = (byte)(((int)(DoSample()*int.MaxValue))%256); buffer[i] = (byte)(DoSampleInteger()%256);
} }
} }
@ -266,7 +271,7 @@ namespace MathNet.Numerics.Random
/// Returns a random number between 0.0 and 1.0. /// Returns a random number between 0.0 and 1.0.
/// </summary> /// </summary>
/// <returns>A double-precision floating point number greater than or equal to 0.0, and less than 1.0.</returns> /// <returns>A double-precision floating point number greater than or equal to 0.0, and less than 1.0.</returns>
protected override sealed double Sample() protected sealed override double Sample()
{ {
if (_threadSafe) if (_threadSafe)
{ {
@ -280,11 +285,26 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns>
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected abstract double DoSample(); protected abstract double DoSample();
/// <summary>
/// Returns a random 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>
/// </summary>
protected virtual int DoSampleInteger()
{
return (int)(DoSample() * int.MaxValue);
}
/// <summary>
/// Returns a random 32-bit signed integer within the specified range.
/// </summary>
/// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param>
protected virtual int DoSampleInteger(int minInclusive, int maxExclusive)
{
return (int)(DoSample()*(maxExclusive - minInclusive)) + minInclusive;
}
} }
} }

25
src/Numerics/Random/SystemRandomSource.cs

@ -112,16 +112,31 @@ namespace MathNet.Numerics.Random
#endif #endif
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
return _random.NextDouble(); return _random.NextDouble();
} }
/// <summary>
/// Returns a random 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>
/// </summary>
protected override int DoSampleInteger()
{
return _random.Next();
}
/// <summary>
/// Returns a random 32-bit signed integer within the specified range.
/// </summary>
/// <param name="minInclusive">The inclusive lower bound of the random number returned.</param>
/// <param name="maxExclusive">The exclusive upper bound of the random number returned. <paramref name="maxExclusive"/> must be greater than or equal to <paramref name="minInclusive"/>.</param>
protected override int DoSampleInteger(int minInclusive, int maxExclusive)
{
return _random.Next(minInclusive, maxExclusive);
}
/// <summary> /// <summary>
/// Fill an array with 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.
/// WARNING: potentially very short random sequence length, can generate repeated partial sequences. /// WARNING: potentially very short random sequence length, can generate repeated partial sequences.

9
src/Numerics/Random/WH1982.cs

@ -37,7 +37,7 @@ using System.Runtime;
namespace MathNet.Numerics.Random namespace MathNet.Numerics.Random
{ {
/// <summary> /// <summary>
/// Wichmann-Hill’s 1982 combined multiplicative congruential generator. /// Wichmann-Hill’s 1982 combined multiplicative congruential generator.
/// </summary> /// </summary>
/// <remarks>See: Wichmann, B. A. &amp; Hill, I. D. (1982), "Algorithm AS 183: /// <remarks>See: Wichmann, B. A. &amp; Hill, I. D. (1982), "Algorithm AS 183:
/// An efficient and portable pseudo-random number generator". Applied Statistics 31 (1982) 188-190 /// An efficient and portable pseudo-random number generator". Applied Statistics 31 (1982) 188-190
@ -106,12 +106,9 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
_xn = (171*_xn)%Modx; _xn = (171*_xn)%Modx;
_yn = (172*_yn)%Mody; _yn = (172*_yn)%Mody;

7
src/Numerics/Random/WH2006.cs

@ -108,12 +108,9 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
_xn = 11600*_xn%Modx; _xn = 11600*_xn%Modx;
_yn = 47003*_yn%Mody; _yn = 47003*_yn%Mody;

29
src/Numerics/Random/Xorshift.cs

@ -68,7 +68,7 @@ namespace MathNet.Numerics.Random
/// <summary> /// <summary>
/// The multiplier to compute a double-precision floating point number [0, 1) /// The multiplier to compute a double-precision floating point number [0, 1)
/// </summary> /// </summary>
const double UlongToDoubleMultiplier = 1.0/(uint.MaxValue + 1.0); const double UlongToDoubleMultiplier = 1.0/4294967296.0; // 1.0/(uint.MaxValue + 1.0)
/// <summary> /// <summary>
/// Seed or last but three unsigned random number. /// Seed or last but three unsigned random number.
@ -252,12 +252,9 @@ namespace MathNet.Numerics.Random
} }
/// <summary> /// <summary>
/// Returns a random number between 0.0 and 1.0. /// Returns a random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </summary> /// </summary>
/// <returns> protected sealed override double DoSample()
/// A double-precision floating point number greater than or equal to 0.0, and less than 1.0.
/// </returns>
protected override sealed double DoSample()
{ {
var t = (_a*_x) + _c; var t = (_a*_x) + _c;
_x = _y; _x = _y;
@ -267,6 +264,26 @@ namespace MathNet.Numerics.Random
return _z*UlongToDoubleMultiplier; return _z*UlongToDoubleMultiplier;
} }
/// <summary>
/// Returns a random 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>
/// </summary>
protected override int DoSampleInteger()
{
var t = (_a * _x) + _c;
_x = _y;
_y = _z;
_c = t >> 32;
_z = t & 0xffffffff;
uint uint32 = (uint)_z;
int int31 = (int)(uint32 >> 1);
if (int31 == int.MaxValue)
{
return DoSampleInteger();
}
return int31;
}
/// <summary> /// <summary>
/// Fills an array with 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.
/// </summary> /// </summary>

12
src/UnitTests/Random/MersenneTwisterTests.cs

@ -50,7 +50,17 @@ namespace MathNet.Numerics.UnitTests.Random
/// Sample known values. /// Sample known values.
/// </summary> /// </summary>
[Test] [Test]
public void SampleKnownValues() public void SampleKnownIntegerValuesSeed42()
{
var mt = new MersenneTwister(42);
Assert.AreEqual(mt.Next(), 804318771);
}
/// <summary>
/// Sample known values.
/// </summary>
[Test]
public void SampleKnownFloatingPointValues()
{ {
var mt = new MersenneTwister(0); var mt = new MersenneTwister(0);
Assert.AreEqual(mt.NextDouble(), 0.5488135023042560); Assert.AreEqual(mt.NextDouble(), 0.5488135023042560);

Loading…
Cancel
Save