本文将介绍如何使用C++ TR1(C++ 标准委员会 Technical Report 1) 提供的随机数生成功能 除了介绍基本的一致随机数生成之外,还会介绍随机样本的可能分布,包括:柏努利分布,二项分布,指数分布,伽马分布,几何分布,正态分布和泊松分布。我会指出一些针对特定分布需要注意的地方,比如参数约定,最后还会给出一些提示,比如如何使用TR1不直接支持的分布产生随机数,比如柯西分布,chi-squared分布和Student t。
Visual Studio 2008 现在通过 feature pack支持TR1扩展(orbit注:微软已经发布了Visual Studio 2008的Services Pack 1,它包含了此前发布的feature pack,以及完整的TR1支持),其它支持TR1的软件或库有 Boost和Dinkumware。 GCC 从4.3版本开始支持 C++ TR1。
为了清楚起见,本文的例子代码都使用了完整的名字空间(namespace)限定,你可以使用using语句来消除这些限定。想要了解更多的例子代码可以看看这篇文章 测试 C++ TR1 随机数生成机制 ,此文还介绍了一个不太成熟的测试框架。
提纲
开始
头文件和名字空间(namespace)
核心引擎
设置种子
从均匀分布生成随机数
离散整数
实数
非均匀分布生成随机数
直接支持的分布
柏努利分布
二项分布
指数分布
伽马分布
几何分布
正态分布(Gaussian)
泊松分布
其它分布
柯西分布(Cauchy)
卡方分布(Chi squared)
T分布(Student t)
开始
头文件和名字空间(namespace)
C++ 的随机数生成类和函数都在
核心引擎
任何伪随机数生成软件的核心就是一个生成均匀分布的随机整数的例程,它被用在引导过程中产生均匀分布的实数,这些均匀分布的实数再通过各种变换(算法)产生其它分布,例如“接受-拒绝”算法,不过这些都需要一个原始的随机数做为起始。
在 C++ TR1 中,有几种不同的(随机数)生成内核,或称之为“引擎”供你选择,下面就是Visual Studio 2008 feature pack所支持的四个引擎类。
linear_congruential 循环使用公式 x(i) = (A * x(i-1) + C) mod M 线性叠加
mersenne_twister 使用了 马特赛旋转演算 算法
subtract_with_carry (带进位线性同余算法)对整数算法循环使用公式 x(i) = (x(i - R) - x(i - S) - cy(i - 1)) mod M
subract_with_carry_01 (改进的带进位线性同余算法)对浮点数算法循环使用公式 x(i) = (x(i - R) - x(i - S) - cy(i - 1)) mod 1
设置种子
每种引擎都有一个 seed() 函数,它接受一个 unsigned long 型参数作为随机数产生的种子。 也可以通过引擎之间独特的模版参数设置种子。
从均匀分布生成随机数
离散整数
uniform_int 类以相同的概率在一个范围内抽取整数,它的构造函数有两个参数,分别表示抽取范围的最大值和最小值,需要注意的是抽取范围是个闭区间,也就是这两个值也可能被抽取到。
例子:
下面面的代码将打印5个从集合:1,2,3,...,52随即抽取的数字,这可能就是一个从一副牌中抽取五张牌的算法模型,每次抽取一张牌,之后归还、洗牌,再抽取下一张牌。
std::tr1::uniform_int
uniform_real 类用于从一个区间产生一个浮点数,它的构造函数有两个参数,就是区间的两个端点,默认值是从0到1。这个类的(随机)值是从半开区间产生的,对于参数 a 和 b,随机值产生的范围是区间:[a, b),换句话说,就是产生的值x满足条件: a <= x < b。
下面的代码从区间 [3, 7) 生成随机数。
std::tr1::uniform_real
非均匀分布生成随机数
C++ TR1 库还支持根据各种分布类(算法)产生非均匀分布的随机数,这些类通过 operator() 方法返回随机样本值。这个方法使用一个引擎类作为参数,例如下面的代码就演示了使用正态分布产生10个随机数。
std::tr1::mt19937 eng; // a core engine classstd::tr1::normal_distribution
下面的例子都假设引擎类 eng 正在使用。
直接支持的分布
柏努利分布
柏努利随机值以概率 p 返回1, 以概率 1-p 返回0值,这个类从柏努利分布类bernoulli_distribution产生样本,它的构造函数只有一个参数,p,这个参数的默认值是0.5。有趣的是bernoulli_distribution类返回值类型不是 int,而是bool 类型, 所以它返回true表示概率返回false表示概率1-p,这是唯一的一个返回布尔值的分布类,也正式这个原因,它成为唯一的一个没有返回值类型模版参数的分布类。
例子:
下面的代码假设已经定义了引擎 eng。 这个例子将在四分之一的时间打印 “six of one” ,剩下的时间打印“half dozen of another”。
std::tr1::bernoulli_distribution bern(0.25);std::cout << (bern(eng) ? "six of one" : "half dozen of another") << std::endl;二项分布
二项分布将n次独立柏努利测试中成功的次数作为返回值,成功的概率是p,产生二项分布随机数的类是 binomial_distribution,它代两个模版参数,就是n的类型和p的类型,默认值分别是int 和 double,构造函数使用参数 n = 1 和 p = 0.5做为默认值。
例子:
下面的代码将模拟掷5次骰子,统计骰子上面是1的次数。(所有的结果都很相似,你可以用来计算其它值出现的次数)

一沙一世界 一花一天堂 掌中握無……

网络编程技术、多媒体技术、PC应用技术
