资源描述
概率论与数理统计课程设计
题目:正态分布随机数生成算法
要编程得到服从均匀分布的伪随机数是容易的。C语言、Java语言等都提供了相应的函数。但是要想生成服从正态分布的随机数就没那么容易了。
得到服从正态分布的随机数的基本思想是先得到服从均匀分布的随机数,再将服从均匀分布的随机数转变为服从正态分布。接下来就先分析三个从均匀分布到正态分布转变的方法。然后编程实现其中的两个方法并对程序实现运作的效果进行统计分析。
1、 方法分析
(1) 利用分布函数的反函数
若要得到分布函数为F(x)的随机变量Y。
可令, 其中u是服从均匀分布的随机变量,有
因而,对于任意的分布函数,只要求出它的反函数,就可以由服从均匀分布的随机变量实例来生成服从该分布函数的随机变量实例。
现在来看正态分布的分布函数,对于,其分布函数为:
显然,要想求其反函数是相当困难的,同时要想编程实现也很复杂。可见,用此种方法来生成服从正态分布的随机变量实例并不可取。
(2) 利用中心极限定理
第二种方法利用林德伯格—莱维(Lindeberg—Levi)中心极限定理:如果随机变量序列独立同分布,并且具有有限的数学期望和方差则对一切有
因此,对于服从均匀分布的随机变量,只要n充分大,随机变量就服从。我们将实现这一方法。
(3) 使用Box Muller方法
先证明:
令,则
令,则有
。
接下来再来得出Box Muller方法:
设为一对相互独立的服从正态分布的随机变量。则有概率密度函数
令,其中,则有分布函数:
令
如果服从均匀分布,则的分布函数即为。
最后,可以用代替,令为,其中,,得:
从而,只需要有两个服从均匀分布的随机变量,就能通过公式
来得到一个服从正态分布的随机变量。用Box Muller方法来生成服从正态分布的随机数是十分快捷方便的。我们也将实现这一方法。
2、 实现与分析
(1) 利用中心极限定理方法的实现与分析
利用中心极限定理来生成随机数的函数(C++语言)编写如下:
const int N = 200;
double getRand()
{
double s = 0;
for (int i = 0; i != N; ++i)
s += double(rand() % 1000) / 1000;
return s;
}
函数生成的随机数是N个[0,1]间服从均匀分布的随机数的和。这里N为200。从而理论上产生的随机数应近似服从,其中n为N,即200,为0.5,为1/12。程序生成了200个随机数,并求出样本均值与样本方差,也即与的最大似然估计:
//生成随机数并存储
double sum, store[200], xi, su = 0, sb = 0, ssb = 0;
int cnt = 0;
sum = 0;
for (int i = 0; i != 200; ++i)
{
xi = getRand();
sum += xi;
store[i] = xi;
}
//得到样本均匀与样本方差
su = sum / 200;
for (int i = 0; i != 200; ++i)
sb += (store[i] - su) * (store[i] - su);
sb /= 200;
ssb = sqrt(sb);
此次选取
,它们将实轴分成11个互不相交的区间,从而将样本值分成11组。程序统计了每组中的样本数量。为方便计算,程序还计算出了:
int segments[12], m = 2;
double x1 = 90, x10 = 108;
memset(segments, 0, sizeof(segments));
for (int i = 0; i != 200; ++i)
{
if (store[i] <= x1)
++segments[0];
else if (store[i] > x10)
++segments[10];
else
++segments[int((store[i] - x1) / m + 1)];
}
cout << 'i' << '\t' << "ni" << endl;
for (int i = 0; i != 11; ++i)
{
cout << i + 1 << '\t' << segments[i];
if (i < 10)
cout << '\t' << fixed << setprecision(2) << (90 + i * 2 - su) / ssb;
cout << endl;
}
程序的最终运行输出如图2-1所示。
图2-1 最终输出结果
对结果的统计如表2-1所示。由表2-1中可见,今并令,则由于,故可认为产生的随机数服从正态分布。
表2-1
利用中心极限定理的方法虽然可以得到服从正态分布的随机数样本,其思想也较为简单,容易想到。但是这种方法每次都要先产生若干个服从均匀分布的随机数样本并求它们的和,因而算法的时间复杂度高。
(2) Box Muller方法的实现与分析
使用Box Muller方法得到随机数的函数如下:
double getRand()
{
double u1 = double(rand() % 10000) / 10000, u2 = double(rand() % 10000) / 10000, r;
r = 20 + 5 * sqrt(-2.0 * (log(u1) / log(e))) * cos(2 * pi * u2);
return r;
}
用此函数得到的随机数样本理论上服从。所实现的程序产生了500个随机变量的样本其他与利用中心极限定理的实现基本相同。程序得到的最终结果如图2-2所示。
图2-2
对结果的统计如表2-2 所示。
表2-2
由表2-2可见,今并令,则由于,故可认为产生的随机数服从正态分布。
Box Muller方法的推导过程较为复杂。但得到的结果却是很令人满意的。只要用两个相互独立的均匀分布就能得到正态分布。而且产生随机数的时间复杂度比利用中心极限定理的方法要低很多。因而若要产生服从正态分布的随机数样例,则Box Muller方法是一个很不错的选择。
展开阅读全文