C++高斯分布随机数的产生

基于Box-Muller算法的高斯分布随机数产生方法

    为了产生高斯分布随机数,有必要先讲讲均匀分布随机数的产生。本文正是采用Box-Muller算法实现高斯分布的,而要借助Box-Muller算法产生高斯分布必须要有现成的均与分布随机数。由此算是真正体验了一把算法是程序的灵魂,感叹算法确实太重要!

   

一,均匀分布的产生思路和方法:

    首先我们必须借助于rand()函数产生一个随机数,必须由这源源不断的无规律的随机数去构造满足其他符合规律的随机数,当然高斯分布就是这其中的一种规律。但是由rand()函数产生的随机数在程序执行过程中总是不变的,所以如果想要产生大量的随机数,rand()必须做一下处理,一种常规的很有效的方式就是将rand()函数植入系统时间种子,代码如下:

srand((unsigned)time(NULL));
x=rand();


    使用这个srand()函数必须将最终的源代码加上头文件,#include "time.h"。

    先假定我们只产生了一个随机数的最简单情况,因为产生批量的成千上万的随机数只是重复同一过程而已。一个均匀分布随机数子函数的实现代码如下:

double UNIFORM()
  {int x;    
   double y;
   srand((unsigned)time(NULL));
   x=rand();      //x就是由基于系统时钟产生的随机数,一个典型的可能的取值可以是:134238
   y=(float)(x0);    //这个随机数和100求余的结果必然得到一个小与100的整数,然后强制转换成浮点数
   y=y/100;    //这个数除以100,会得到一个小与1的数。
   return y;
} 


    由这个函数产生的随机数是介于(0,1)之间的,理论上可以产生(0,1)之间的任何数,并且任何两个数的取值概率从统计上来讲必然相等,所以返回的y必然就服从均匀分布。

 

二,Box-Muller算法:

  Box-Muller算法正是利用均匀分布产生高斯分布随机数,算法如下:

    上式中的U1和U2就是两个均匀分布随机数,经过这样的一种计算之后就能产生一个Z服从均匀分布的随机数,这看起来太神奇了,不得不佩服这个算法。说明一下,上面的三个式子,前两个取任何一个都可以用作算法,取正弦还是余弦是无所谓的。另外一点,上面的式子仅仅只能产生标准的高斯分布,若要产生给定的均值和方差其实也很简单。

Y=u+(Z*sigma)

    上式中的u,sigma就是可以自己手动定义的期望和方差。

    好了,基于这个算法,我批量的产生了10000个数,来看看最终的程序代码。

 

三,完整程序代码:

#include <iostream>
#include <time.h>
#include <iomanip>
#include <math.h>
#include <fstream>
#define PI 3.14159
using namespace std;
void UNIFORM(double *);  //UINFORM函数声明
int x = 0;   //这里定义x一个全局变量并且初始付值0,这个的功用将会在子函数UNIFORM中得以体现
int main()
{
	int i, j;
	double A, B, C, E, D, r;
	double uni[2];
	double *p;
	srand((unsigned)time(NULL));  //随机数种子采用系统时钟
	ofstream outfile("Gauss.txt", ios::out);  //定义文件对象
	cout << "输入期望和方差:" << endl;
	cin >> E >> D;
	for (j = 0; j<10000; j++)
	{
		UNIFORM(&uni[0]);  //调用UNIFORM函数产生2个均匀分布的随机数并存入数组nui[2]
		A = sqrt((-2)*log(uni[0]));
		B = 2 * PI*uni[1];
		C = A*cos(B);
		r = E + C*D;    //E,D分别是期望和方差
		outfile << r << "   ";  //将数据C输出到被定义的文件中

	}
	return 0;
}
void UNIFORM(double *p)
{
	int i, a;
	double f;
	for (i = 0; i<2; i++, x = x + 689)
	{
		a = rand() + x;  //加上689是因为系统产生随机数的更换频率远远不及程序调用函数的时间
		a = a%1000;
		f = (double)a;
		f = f / 1000.0;
		*p = f;
		p++;
	}
}


    由于本程序执行之后会产生10000个数据,所以没有让他在终端中展示出来,而是利用  outfile<<r<<"   ";指令将所有数据输出到F:\VC6.0\MSDev98\Bin\Gauss.txt记事本文件中。这是为了便于做Matlab统计仿真的需要。我执行了两次程序,输入期望和方差为(0,1)和(0,4)。

 

四,Matlab仿真结果:

 


     N(0,1) 



                                                                                                                                                      N(0,4)

 

 

 

    Matlab读入利用C++程序产生的Gauss.txt文本文件绘制直方图的代码如下:

load F:\VC6.0\MSDev98\Bin\Gauss.txt;   %读入数据文件
y=Gauss;   
x=-20:0.2:20;
hist(y,x);    %绘制直方图

五,小结:   

    纵观其实整个过程很简单,最关键的只有两点,一是均匀分布产生的方法,二是套用Box-Muller算法作为整个程序的灵魂。还是那句话,不得不承认算法才是王道。另外由于我习惯了C++,所以程序用的C++写的,其实用C完全可以,两者的区别在这个小程序里仅仅体现在头文件,输入输出语句,文件操作语句这一点点差别而已。

  • 22
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值