.NET 随机数生成器和分布






4.89/5 (114投票s)
2006 年 8 月 9 日
20分钟阅读

439306

29293
提供了一个完全托管的类库,提供各种随机数生成器和分布
- 下载类库 (.NET 2.0) - 42.5 Kb
- 下载类库 (.NET 1.1) - 39.1 Kb
- 下载演示应用程序 (.NET 2.0) - 194.3 Kb
- 下载类库源代码 (VS 2005) - 102.3 Kb
- 下载演示应用程序源代码 (VS 2005) - 291.6 Kb
- 下载文档 (CHM 文件) - 179.8 Kb
目录
引言
本文的想法诞生于 2004 年,当时我正在撰写我的学士论文,其中包括实现一个流量控制算法的模拟和测试环境。由于各种原因,我选择将其实现为一个使用 C# 开发的托管应用程序。我唯一后悔这个选择的时候是当我开始实现数据流量模拟时,这需要分布式的随机变量。不幸的是,我在 .NET 框架类库或任何其他资源中都找不到任何免费提供的随机数分布的托管实现。因此,我亲自实现了所需的随机数分布。从那时起,我一直有一个想法,即基于这些少量实现创建一个类库并在此处 CodeProject 上发布,但我一直没有真正有时间去实现它。直到现在。
随机类库
随机类库包含随机数生成器和随机数分布的抽象基类,以及从两者派生出的各种具体类。在我开始描述这些类之前,我必须提及,所有生成(分布式)随机数的算法都不是我的智力成果,因为我不是一位杰出的数学家。因此,本文以及源代码都包含对相关知识资源的引用。
随机数生成器
抽象基类“Generator”
Generator
类型声明了所有随机数生成器的通用功能。这包括 System.Random
类型提供的一个,以及一些扩展。因此,该类还额外声明了 NextDouble
方法的两个重载、一个 NextBoolean
方法以及重置随机数生成器的可能性。这在使用伪随机数生成器时非常有用。下表列出了所有抽象成员及其简要说明。
抽象成员 | 描述 |
---|---|
bool CanReset { get; } |
获取一个值,指示随机数生成器是否可以重置,以便它再次生成相同的随机数序列。 |
bool Reset(); |
重置随机数生成器,使其再次生成相同的随机数序列。 如果随机数生成器已重置,则返回 true ;否则,返回 false 。 |
int Next(); |
返回一个小于 Int32.MaxValue 的非负随机数;也就是说,返回值范围包括 0 但不包括 Int32.MaxValue 。 |
int Next( |
返回一个小于指定最大值的非负随机数;也就是说,返回值范围包括 0 但不包括 maxValue。 maxValue 必须大于或等于 0。 |
int Next( |
返回指定范围内的随机数;也就是说,返回值范围包括 minValue 但不包括 maxValue。 maxValue 必须大于或等于 minValue。 |
double NextDouble(); |
返回一个小于 1.0 的非负浮点随机数;也就是说,返回值范围包括 0.0 但不包括 1.0。 |
double NextDouble( |
返回一个小于指定最大值的非负浮点随机数;也就是说,返回值范围包括 0.0 但不包括 maxValue。 maxValue 必须大于或等于 0.0。 |
double NextDouble( |
返回指定范围内的浮点随机数;也就是说,返回值范围包括 minValue 但不包括 maxValue。 maxValue 必须大于或等于 minValue。 minValue 和 maxValue 之间的距离必须小于或等于 Double.MaxValue 。 |
bool NextBoolean(); |
返回一个随机布尔值。 |
void NextBytes( |
用随机数填充指定字节数组的元素。 字节数组的每个元素都被设置为大于或等于 0 且小于或等于 Byte.MaxValue 的随机数。 |
派生自“Generator”的类
目前,该库提供了四个从 Generator
派生出的类。它们在下表中列出,并附有简短描述和进一步阅读的链接。
实现 | 可重置 | 描述 / 链接 |
---|---|---|
ALFGenerator | true |
表示一个附加滞后斐波那契伪随机数生成器,带有一些额外的 Next 方法。此类型基于 Boost Random Number Library 中的实现。它使用模数 232,默认情况下使用“滞后”418 和 1279。这可以通过相关的 ShortLag 和 LongLag 属性进行调整。一些流行的对在 维基百科 - 滞后斐波那契生成器 上有介绍。 |
MT19937Generator | true |
表示一个周期为 219937-1 的梅森旋转伪随机数生成器,带有一些额外的 Next 方法。此类型基于 梅森旋转主页 上提供的信息和实现。 |
StandardGenerator | true |
表示一个简单的伪随机数生成器。 此类型内部使用 System.Random 类型的一个实例来生成伪随机数。 |
XorShift128Generator | true |
表示一个周期为 2128-1 的异或移位伪随机数生成器,带有一些额外的 Next 方法。此类型基于 CP 文章“System.Random 的快速替代品”中提供的实现以及 George Marsaglia 在论文“异或移位 RNGs”中发表的异或移位随机数生成器的理论背景。 |
随机数分布
抽象基类“Distribution”
Distribution
类声明了所有随机数分布的通用功能。其必须由继承者实现的抽象成员是一些提供分布特征信息和 NextDouble
方法的属性。下表列出了所有抽象成员及其简要描述。
抽象成员 | 描述 |
---|---|
double Minimum { get; } |
获取分布式随机数的最小可能值。 |
double Maximum { get; } |
获取分布式随机数的最大可能值。 |
double Mean { get; } |
获取分布式随机数的平均值。 如果无法计算平均值,将返回 Double.NaN 常量。 |
double Median { get; } |
获取分布式随机数的中位数。 如果无法计算中位数,将返回 Double.NaN 常量。 |
double Variance { get; } |
获取分布式随机数的方差。 如果无法计算方差,将返回 Double.NaN 常量。 |
double[] Mode { get; } |
获取分布式随机数的众数。 如果无法计算众数,将返回一个空数组。 |
double NextDouble(); |
返回一个分布式浮点随机数。 |
除了其抽象成员外,Distribution
类型还提供了一些所有随机数分布共有的实现细节。由于分布式随机数的计算必然需要一个随机数生成器,因此 generator
字段存储着一个 Generator
类的实例。该实例可通过其各自的属性供继承者访问。此外,定义了两个 protected
构造函数:一个接受用户定义的 Generator
对象,另一个是应用 StandardGenerator
类型实例的标准构造函数。Distribution
类型还提供与 Generator
类相同的重置功能。实际上,它只是转发存储的 Generator
实例的结果,因为随机数分布只有在其底层随机数生成器可重置时才能重置。
public abstract class Distribution
{
protected Generator Generator
{
get { return this.generator; }
set { this.generator = value; }
}
private Generator generator;
protected Distribution() : this(new StandardGenerator())
{
}
protected Distribution(Generator generator)
{
if (generator == null)
{
string message = string.Format(null,
ExceptionMessages.ArgumentNull, "generator");
throw new ArgumentNullException("generator", message);
}
this.generator = generator;
}
public bool CanReset
{
get { return this.generator.CanReset; }
}
public virtual bool Reset()
{
return this.generator.Reset();
}
...
}
派生自“Distribution”的类
随机类库目前为各种连续和离散分布提供了 Distribution
的继承者。它们在下表中列出,并附有简短描述、进一步阅读的链接以及范围和特定分布参数的信息。
实现 | 参数 / 范围 | 描述 / 链接 | ||
---|---|---|---|---|
BetaDistribution |
|
提供 Beta 分布随机数的生成。 此类型基于 维基百科 - Beta 分布 和 Xycoon - Beta 分布 中提供的信息。 |
||
BetaPrimeDistribution |
|
提供 Beta-Prime 分布随机数的生成。 此类型基于 Xycoon - 逆 Beta 分布 中提供的信息。 |
||
CauchyDistribution |
|
提供 Cauchy 分布随机数的生成。 此类型基于 维基百科 - Cauchy 分布 和 Xycoon - Cauchy 分布 中提供的信息。 |
||
ChiDistribution |
|
提供 Chi 分布随机数的生成。 此类型基于 维基百科 - Chi 分布 中提供的信息。 |
||
ChiSquareDistribution |
|
提供卡方分布随机数的生成。 此类型基于 维基百科 - 卡方分布 中提供的信息。 |
||
ContinuousUniformDistribution |
|
提供连续均匀分布随机数的生成。 此类型基于 维基百科 - 均匀分布 (连续) 中提供的信息。 |
||
ErlangDistribution |
|
提供爱尔兰分布随机数的生成。 此类型基于 维基百科 - 爱尔兰分布 和 Xycoon - 爱尔兰分布 中提供的信息。 |
||
ExponentialDistribution |
|
提供指数分布随机数的生成。 此类型基于 维基百科 - 指数分布 中提供的信息。 |
||
FisherSnedecorDistribution |
|
提供 Fisher-Snedecor 分布随机数的生成。 此类型基于 维基百科 - F 分布 中提供的信息。 |
||
FisherTippettDistribution |
|
提供 Fisher-Tippett 分布随机数的生成。 此类型基于 维基百科 - Fisher-Tippett 分布 中提供的信息。 |
||
GammaDistribution |
|
提供 Gamma 分布随机数的生成。 此类型基于 维基百科 - Gamma 分布 中提供的信息。 |
||
LaplaceDistribution |
|
提供 Laplace 分布随机数的生成。 此类型基于 维基百科 - Laplace 分布 中提供的信息。 |
||
LognormalDistribution |
|
提供对数正态分布随机数的生成。 此类型基于 维基百科 - 对数正态分布 和 Boost Random Number Library 中的实现。 |
||
NormalDistribution |
|
提供正态分布随机数的生成。 此类型基于 维基百科 - 正态分布 和 通信网络类库 中的实现。 |
||
ParetoDistribution |
|
提供 Pareto 分布随机数的生成。 此类型基于 维基百科 - Pareto 分布 和 Xycoon - Pareto 分布 中提供的信息。 |
||
PowerDistribution |
|
提供幂分布随机数的生成。 此类型基于 Xycoon - 幂分布 中提供的信息。 |
||
RayleighDistribution |
|
提供瑞利分布随机数的生成。 此类型基于 维基百科 - 瑞利分布 中提供的信息。 |
||
StudentsTDistribution |
|
提供 t 分布随机数的生成。 此类型基于 维基百科 - 学生 t 分布 和 Xycoon - 学生 t 分布 中提供的信息。 |
||
TriangularDistribution |
|
提供三角分布随机数的生成。 此类型基于 维基百科 - 三角分布 和 Boost Random Number Library 中的实现。 |
||
WeibullDistribution |
|
提供威布尔分布随机数的生成。 此类型基于 维基百科 - 威布尔分布 中提供的信息。 |
实现 | 参数 / 范围 | 描述 | ||
---|---|---|---|---|
BernoulliDistribution |
|
提供伯努利分布随机数的生成。 此类型基于 维基百科 - 伯努利分布 中提供的信息。 |
||
BinomialDistribution |
|
提供二项分布随机数的生成。 此类型基于 维基百科 - 二项分布 中提供的信息。 |
||
DiscreteUniformDistribution |
|
提供离散均匀分布随机数的生成。 此类型基于 维基百科 - 均匀分布 (离散) 中提供的信息。 |
||
GeometricDistribution |
|
提供几何分布随机数的生成。 此类型基于 维基百科 - 几何分布 和 通信网络类库 中的实现。 |
||
PoissonDistribution |
|
提供泊松分布随机数的生成。 此类型基于 维基百科 - 泊松分布 和 通信网络类库 中的实现。 |
除了继承的成员之外,所有派生自 Distribution
的类还有一些共同的相似之处。首先,所有分布都提供两个构造函数:一个接受用户定义的 Generator
对象作为底层随机数生成器,另一个是标准构造函数,为此目的使用 StandardGenerator
类型的一个实例。
其次,每个分布都提供方法,允许您确定一个值对于其特定参数是否有效,因此可以通过所属属性进行分配。这些方法遵循命名方案“IsValid{parameter}”,并且为了保持一致性,对于值范围不受限制的参数也可用。
此外,从 Distribution
派生的类在可能的情况下利用 helper 变量来加速随机数生成。这些 helper 存储仅依赖于分布参数的中间结果,因此在 NextDouble
的后续执行中无需重新计算。helper 变量的计算封装在 UpdateHelperVariables
方法中,该方法在构造期间以及每当涉及 helper 计算的分布参数发生更改时被调用。以下代码片段取自 PoissonDistribution
类型,应能说明上述解释。
public class PoissonDistribution : Distribution
{
public double lambda;
private double helper1;
public double Lambda
{
get { return this.lambda; }
set
{
if (this.IsValidLambda(value))
{
this.lambda = value;
this.UpdateHelpers();
}
}
}
public PoissonDistribution() : this(new StandardGenerator())
{
}
public PoissonDistribution(Generator generator) : base(generator)
{
this.lambda = 1.0;
this.UpdateHelpers();
}
public bool IsValidLambda(double value)
{
return value > 0.0;
}
private void UpdateHelpers()
{
this.helper1 = Math.Exp(-1.0 * this.lambda);
}
public double NextDouble()
{
double count = 0;
for (double product =
this.generator.NextDouble(); product >= this.helper1;
product *= this.generator.NextDouble())
{
count++;
}
return count;
}
...
版本历史
1.4 |
|
1.3 |
|
1.2 |
|
1.1 |
|
1.0 |
|
版权声明
随机类库是自由软件。您可以根据自由软件基金会发布的 GNU 宽通用公共许可证(版本 2.1 或您选择的任何更高版本)的条款重新分发和/或修改它。本库的发布是为了希望它有用,但不提供任何担保,甚至不包括适销性或特定用途适用性的默示担保。有关更多详细信息,请参阅 GNU 宽通用公共许可证。您应该已随本库收到一份 GNU 宽通用公共许可证的副本。如果未收到,请写信给 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA。
RandomTester 应用程序
我开始开发 RandomTester 应用程序是在我为学士论文实现第一个随机数分布时。当时,它唯一的目的是可视化生成的随机数的分布以及特定分布参数对其的影响。在开发随机类库的过程中,我完善了这种可视化,并添加了随机数生成器和分布的性能测试。
测试随机数生成器
RandomTester 应用程序允许您测试和比较随机数生成器的性能。下图显示了运行此测试后的用户界面。

所有派生自 Generator
的类都列在左侧。它们可以通过单击各自列表条目逐个选择/取消选择,也可以通过使用“全选”或“全不选”按钮一次性选择/取消选择。在这些按钮下方,您可以指定每个生成器必须生成多少个样本来基准测试它们的性能。最后,必须选择应该测试哪些 Next
方法——由 Generator
类型声明并在派生类中实现。随机数生成器的性能以每秒调用次数衡量。结果显示在一个数据网格中,该数据网格包含每个随机数生成器的一行和每个测试的 Next
方法的一列。
测试随机数分布
随机数分布可以通过两种方式进行测试。首先,可以进行性能测试,类似于为随机数生成器提供的性能测试。其次,可以可视化生成的随机数的分布以及特定分布参数对其的影响。这些测试的用户界面如下图所示。

如前所述,性能测试类似于随机数生成器基准测试。在左侧,列出了所有派生自 Distribution
的类,可以通过单击各自的列表条目逐个选择/取消选择,也可以通过使用“全选”或“全不选”按钮一次性选择/取消选择。此外,可以指定每个分布在基准测试期间必须生成的样本数量,以及一个底层随机数生成器。后一个调整提供了使用派生自 Generator
的类或分布默认值。如果选择了 Generator
的继承者,则使用其构造函数实例化测试的分布,该构造函数接受此类对象。否则,使用标准构造函数。所选随机数分布的性能表示为生成指定数量样本所需的时间。结果以升序显示在文本框中。
与两种性能测试不同,可视化测试的主要焦点不是性能,而是测试单个随机数分布。因此,它采用 ZedGraphControl 来显示生成的随机数分布的直方图,即不同值出现的频率,或者更准确地说,它们出现的可能性(概率密度函数)。
对于离散分布,这可以通过计算离散值的出现次数并除以生成的样本总数轻松完成。不幸的是,大多数随机数分布是连续的,并且具有相当大的范围。因此,给定值被多次生成的概率非常低,即使生成了许多数字。这就是为什么可视化测试将生成的样本域划分为指定数量的区间,然后显示这些区间内的值出现的可能性。对于离散随机数分布也使用这样的直方图,因为只要区间数量等于或大于离散值数量,它就会提供相同的结果。在这种情况下,分布类型之间的复杂区分变得冗余。
在左上角,一个下拉列表允许您从所有派生自 Distribution
的类中选择要可视化的分布。在该列表下方,一个分组框显示所选分布的当前特征。第二个分组框允许您调整特定参数。根据所选分布,参数的更改还会导致其一个或多个特征发生更改。与分布直接相关的最终调整是选择一个底层随机数生成器,该生成器允许您选择分布默认值或派生自 Generator
的类。
任何其他设置都与随机数分布的可视化有关。您可以指定用于创建直方图的样本和分段数量,直方图曲线是否应该平滑,以及是否使用特定边界(即任何超出边界的生成随机数将被忽略)。
如上图所示,可以同时显示多个直方图。这允许您检查参数对随机数分布的影响,甚至比较不同的分布。每个新生成的直方图都作为单独的曲线绘制。测试分布的名称和参数值会添加到图例中。除了直方图之外,左下角的文本框还显示了生成随机数所需的时间,以及它们的最小值、最大值、平均值和方差。
版本历史
1.2 |
|
1.1 |
|
1.0 |
|
版权声明
RandomTester 是自由软件。您可以根据自由软件基金会发布的 GNU 通用公共许可证(版本 2 或任何更高版本)的条款重新分发和/或修改它。本程序是希望它有用而发布,但不提供任何担保,甚至不包括适销性或特定用途适用性的默示担保。有关更多详细信息,请参阅 GNU 通用公共许可证。您应该已随本程序收到一份 GNU 通用公共许可证的副本;如果未收到,请写信给 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA。
参考文献
- 维基百科 - 随机数生成器
- 梅森旋转主页
- System.Random 的快速替代品
- George Marsaglia 撰写的论文《Xorshift RNGs》
- 维基百科 - 概率分布
- MathWorld - 统计分布
- Xycoon - 统计分布
- Boost 随机数库
- 通信网络类库
- 一个灵活的 .NET 图表库
文章历史
- 2007 年 5 月 29 日 - 文章已编辑并发布到 CodeProject.com 主文章库