原文:【原创】开源Math.NET基础数学类库使用(13)C#实现其他随机数生成器
本博客所有文章分类的总目录:http://www.cnblogs.com/asxinyu/p/4288836.html
开源Math.NET基础数学类库使用总目录:http://www.cnblogs.com/asxinyu/p/4329737.html
前言
真正意义上的随机数(或者随机事件)在某次产生过程中是按照实验过程中表现的分布概率随机产生的,其结果是不可预测的,是不可见的。而计算机中的随机函数是按照一定算法模拟产生的,其结果是确定的,是可见的。我们可以这样认为这个可预见的结果其出现的概率是100%。所以用计算机随机函数所产生的“随机数”并不随机,是伪随机数。伪随机数的作用在开发中的使用非常常见,因此.NET在System命名空间,提供了一个简单的Random随机数生成类型。但这个类型并不能满足所有的需求,本节开始就将陆续介绍Math.NET中有关随机数的扩展以及其他伪随机生成算法编写的随机数生成器。
今天要介绍的是Math.NET中扩展的其他随机数生成算法。
如果本文资源或者显示有问题,请参考 本文原文地址:http://www.cnblogs.com/asxinyu/p/4301555.html
http://zh.wikipedia.org/wiki/随机数
随机数是专门的随机试验的结果。
在统计学的不同技术中需要使用随机数,比如在从统计总体中抽取有代表性的样本的时候,或者在将实验动物分配到不同的试验组的过程中,或者在进行蒙特卡罗模拟法计算的时候等等。产生随机数有多种不同的方法。这些方法被称为随机数生成器。随机数最重要的特性是它在产生时后面的那个数与前面的那个数毫无关系。
真正的随机数是使用物理现象产生的:比如掷钱币、骰子、转轮、使用电子元件的噪音、核裂变等等。这样的随机数生成器叫做物理性随机数生成器,它们的缺点是技术要求比较高。在实际应用中往往使用伪随机数就足够了。这些数列是“似乎”随机的数,实际上它们是通过一个固定的、可以重复的计算方法产生的。它们不真正地随机,因为它们实际上是可以计算出来的,但是它们具有类似于随机数的统计特征。这样的生成器叫做伪随机数生成器。在真正关键性的应用中,比如在密码学中,人们一般使用真正的随机数。
1.Math.NET的其他随机数生成算法
Math.NET在MathNet.Numerics.Random命名空间下包括了若干个其他随机数生成算法,基本介绍如下:
1.Mcg31m1类 与 Mcg59 类,都属于 矩阵同余发生器,矩阵同余发生器是乘同余线性发生器的一个推广;2者的参数有些差别;
3.MersenneTwister,Mersenne Twister算法译为马特赛特旋转演算法,是伪随机数发生器之一,其主要作用是生成伪随机数。此算法是Makoto Matsumoto (松本)和Takuji Nishimura (西村)于1997年开发的,基于有限二进制字段上的矩阵线性再生。可以快速产生高质量的伪随机数,修正了古老随机数产生算法的很多缺陷。 Mersenne Twister这个名字来自周期长度通常取Mersenne质数这样一个事实。常见的有两个变种Mersenne Twister MT19937和Mersenne Twister MT19937-64。Math.NET实现的版本是前者(Mersenne Twister MT19937)。介绍
4.Mrg32k3a,又叫 素数模乘同余法,素数模乘同余发生器是提出的一个统计性质较好和周期较大的发生器,目前是使用最广的一种均匀随机数发生器下面给出两组经检验统计性质是良好的素数模乘同余发生器;
5.Palf,是一个并行加法滞后的斐波那契伪随机数字生成器。
6.WH1982与WH2006类,是乘线性同余法,也叫积式发生器,Math.NET实现的2个版本方便是1982和2006,代表作者发布该算法论文的2个时间,可以参考作者的2篇论文:
1.Wichmann, B. A. & Hill, I. D. (1982), "Algorithm AS 183:An efficient and portable pseudo-random number generator". Applied Statistics 31 (1982) 188-190
2. Wichmann, B. A. & Hill, I. D. (2006), "Generating good pseudo-random numbers".Computational Statistics & Data Analysis 51:3 (2006) 1614-1622
8.Xorshift类,实现的是George Marsaglia,在论文“Xorshift RNGs”提出的一个算法,原理可以参考这篇论文:http://www.jstatsoft.org/v08/i14/paper;
2.Math.NET扩展随机数生成算法的实现
上面已经已经对Math.NET扩展的几个随机数生成算法进行了介绍,对于一般人来说,直接用就可以了,但对于特殊的人来说,可能要用到其中一种,可以直接使用C#进行调用即可,当然为了节省大家的时间,这里对Math.NET的实现做一个简单的介绍,这样大家可以更加快速的扩展自己的算法,同时也可以了解实现的原理,对Math.NET有一个更加深入的了解。
Math.NET对随机数的扩展也是借用了System.Random类,在它的基础上实现了一个随机数发生器的基类:RandomSource,所有的扩展算法都实现该类,这样使用RandomSource就非常方便。RandomSource的结构很简单,对System.Random进行了简单的封装,增加了几个直接生成其他类型随机数的方法,并都可以在继承中使用。其源码如下:
public abstract class RandomSource : System.Random
{
readonly bool _threadSafe;
readonly object _lock = new object(); /// <summary>
/// Initializes a new instance of the <see cref="RandomSource"/> class using
/// the value of <see cref="Control.ThreadSafeRandomNumberGenerators"/> to set whether
/// the instance is thread safe or not.
/// </summary>
protected RandomSource() : base(RandomSeed.Robust())
{
_threadSafe = Control.ThreadSafeRandomNumberGenerators;
} /// <summary>
/// Initializes a new instance of the <see cref="RandomSource"/> class.
/// </summary>
/// <param name="threadSafe">if set to <c>true</c> , the class is thread safe.</param>
/// <remarks>Thread safe instances are two and half times slower than non-thread
/// safe classes.</remarks>
protected RandomSource(bool threadSafe) : base(RandomSeed.Robust())
{
_threadSafe = threadSafe;
} /// <summary>
/// Fills an array with uniform random numbers greater than or equal to 0.0 and less than 1.0.
/// </summary>
/// <param name="values">The array to fill with random values.</param>
public void NextDoubles(double[] values)
{
if (_threadSafe)
{
lock (_lock)
{
for (var i = ; i < values.Length; i++)
{
values[i] = DoSample();
}
}
}
else
{
for (var i = ; i < values.Length; i++)
{
values[i] = DoSample();
}
}
} /// <summary>
/// Returns an infinite sequence of uniform random numbers greater than or equal to 0.0 and less than 1.0.
/// </summary>
public IEnumerable<double> NextDoubleSequence()
{
for (int i = ; i < ; i++)
{
yield return NextDouble();
} var buffer = new double[];
while (true)
{
NextDoubles(buffer);
for (int i = ; i < buffer.Length; i++)
{
yield return buffer[i];
}
}
} /// <summary>
/// Returns a nonnegative random number.
/// </summary>
/// <returns>
/// A 32-bit signed integer greater than or equal to zero and less than <see cref="F:System.Int32.MaxValue"/>.
/// </returns>
public override sealed int Next()
{
if (_threadSafe)
{
lock (_lock)
{
return (int)(DoSample()*int.MaxValue);
}
} return (int)(DoSample()*int.MaxValue);
} /// <summary>
/// Returns a random number less then a specified maximum.
/// </summary>
/// <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>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="maxValue"/> is negative. </exception>
public override sealed int Next(int maxValue)
{
if (maxValue <= )
{
throw new ArgumentException(Resources.ArgumentMustBePositive);
} if (_threadSafe)
{
lock (_lock)
{
return (int)(DoSample()*maxValue);
}
} return (int)(DoSample()*maxValue);
} /// <summary>
/// Returns a random number within a specified range.
/// </summary>
/// <param name="minValue">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>
/// <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.
/// </returns>
/// <exception cref="T:System.ArgumentOutOfRangeException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>. </exception>
public override sealed int Next(int minValue, int maxValue)
{
if (minValue > maxValue)
{
throw new ArgumentException(Resources.ArgumentMinValueGreaterThanMaxValue);
} if (_threadSafe)
{
lock (_lock)
{
return (int)(DoSample()*(maxValue - minValue)) + minValue;
}
} return (int)(DoSample()*(maxValue - minValue)) + minValue;
} /// <summary>
/// Fills an array with random numbers within a specified range.
/// </summary>
/// <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="maxValue">The exclusive upper bound of the random number returned. <paramref name="maxValue"/> must be greater than or equal to <paramref name="minValue"/>.</param>
public void NextInt32s(int[] values, int minValue, int maxValue)
{
if (_threadSafe)
{
lock (_lock)
{
for (var i = ; i < values.Length; i++)
{
values[i] = (int)(DoSample()*(maxValue - minValue)) + minValue;
}
}
}
else
{
for (var i = ; i < values.Length; i++)
{
values[i] = (int)(DoSample()*(maxValue - minValue)) + minValue;
}
}
} /// <summary>
/// Returns an infinite sequence of random numbers within a specified range.
/// </summary>
/// <param name="minValue">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>
public IEnumerable<int> NextInt32Sequence(int minValue, int maxValue)
{
for (int i = ; i < ; i++)
{
yield return Next(minValue, maxValue);
} var buffer = new int[];
while (true)
{
NextInt32s(buffer, minValue, maxValue);
for (int i = ; i < buffer.Length; i++)
{
yield return buffer[i];
}
}
} /// <summary>
/// Fills the elements of a specified array of bytes with random numbers.
/// </summary>
/// <param name="buffer">An array of bytes to contain random numbers.</param>
/// <exception cref="T:System.ArgumentNullException"><paramref name="buffer"/> is null. </exception>
public override void NextBytes(byte[] buffer)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
} if (_threadSafe)
{
lock (_lock)
{
for (var i = ; i < buffer.Length; i++)
{
buffer[i] = (byte)(((int)(DoSample()*int.MaxValue))%);
}
} return;
} for (var i = ; i < buffer.Length; i++)
{
buffer[i] = (byte)(((int)(DoSample()*int.MaxValue))%);
}
} /// <summary>
/// Returns a random number between 0.0 and 1.0.
/// </summary>
/// <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()
{
if (_threadSafe)
{
lock (_lock)
{
return DoSample();
}
} return DoSample();
} /// <summary>
/// Returns a random number between 0.0 and 1.0.
/// </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();
}
在扩展随机数生成算法的时候,直接继承该类即可,看一下Mcg59的实现源码:
public class Mcg59 : RandomSource
{
const ulong Modulus = ;
const ulong Multiplier = ;
const double Reciprocal = 1.0/Modulus;
ulong _xn; /// <summary>
/// Initializes a new instance of the <see cref="Mcg59"/> class using
/// a seed based on time and unique GUIDs.
/// </summary>
public Mcg59() : this(RandomSeed.Robust())
{
} /// <summary>
/// Initializes a new instance of the <see cref="Mcg59"/> class using
/// a seed based on time and unique GUIDs.
/// </summary>
/// <param name="threadSafe">if set to <c>true</c> , the class is thread safe.</param>
public Mcg59(bool threadSafe) : this(RandomSeed.Robust(), threadSafe)
{
} /// <summary>
/// Initializes a new instance of the <see cref="Mcg59"/> class.
/// </summary>
/// <param name="seed">The seed value.</param>
/// <remarks>If the seed value is zero, it is set to one. Uses the
/// value of <see cref="Control.ThreadSafeRandomNumberGenerators"/> to
/// set whether the instance is thread safe.</remarks>
public Mcg59(int seed)
{
if (seed == )
{
seed = ;
} _xn = (uint)seed%Modulus;
} /// <summary>
/// Initializes a new instance of the <see cref="Mcg59"/> class.
/// </summary>
/// <param name="seed">The seed value.</param>
/// <remarks>The seed is set to 1, if the zero is used as the seed.</remarks>
/// <param name="threadSafe">if set to <c>true</c> , the class is thread safe.</param>
public Mcg59(int seed, bool threadSafe) : base(threadSafe)
{
if (seed == )
{
seed = ;
} _xn = (uint)seed%Modulus;
} /// <summary>
/// Returns a random number between 0.0 and 1.0.
/// </summary>
/// <returns>
/// 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;
_xn = (_xn*Multiplier)%Modulus;
return ret;
} /// <summary>
/// Fills an array with random numbers greater than or equal to 0.0 and less than 1.0.
/// </summary>
/// <remarks>Supports being called in parallel from multiple threads.</remarks>
public static void Doubles(double[] values, int seed)
{
if (seed == )
{
seed = ;
} ulong xn = (uint)seed%Modulus; for (int i = ; i < values.Length; i++)
{
values[i] = xn*Reciprocal;
xn = (xn*Multiplier)%Modulus;
}
} /// <summary>
/// Returns an array of random numbers greater than or equal to 0.0 and less than 1.0.
/// </summary>
/// <remarks>Supports being called in parallel from multiple threads.</remarks>
[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;
} /// <summary>
/// Returns an infinite sequence of random numbers greater than or equal to 0.0 and less than 1.0.
/// </summary>
/// <remarks>Supports being called in parallel from multiple threads, but the result must be enumerated from a single thread each.</remarks>
public static IEnumerable<double> DoubleSequence(int seed)
{
if (seed == )
{
seed = ;
} ulong xn = (uint)seed%Modulus; while (true)
{
yield return xn*Reciprocal;
xn = (xn*Multiplier)%Modulus;
}
}
}
随机数的使用大家都很熟练,和Random类差不多,上述扩展的算法中,也包括了很多 静态方法,可以直接使用。这里不再举例说明。
3.资源
源码下载:http://www.cnblogs.com/asxinyu/p/4264638.html
如果本文资源或者显示有问题,请参考 本文原文地址:http://www.cnblogs.com/asxinyu/p/4301555.html