风蚀之月

C++正态随机数生成

03 May 2012 c++ 正态随机

最近碰到了c++生成正态随机数的问题,在这里把查到的资料整理一下。

正态随机数最便捷的方法是使用libstdc++,在C++11. 26.5-1版本后标准库中已经加入了来处理对随机数的生成。下面的代码就是一个简单的生成过程:

#include <random>
#include <time.h>
#include <iostream>

typedef std::ranlux64_base_01 Myeng;  
typedef std::normal_distribution<double> Mydist;

int main( int argc, char* args[] )
{

  Myeng eng;  
  eng.seed(time(NULL));//将时间作为seed
  Mydist dist(1.5, 2.0);  
  Mydist::input_type engval = eng();  
  Mydist::result_type distval = dist(eng); 

  distval = distval; // 防止出现"xxxx未使用"的报错  
  engval = engval;  

  std::cout<<d<<std::endl;
  std::cout << "期望== " << dist.mean() << std::endl;  
  std::cout << "标准差== " << dist.sigma() << std::endl;  

  dist.reset(); // 清除缓存值  
  std::cout << "随机数1 == " << dist(eng) << std::endl;  
  std::cout << "随机数2 == " << dist(eng) << std::endl;  
  std::cout << "随机数3 == " << dist(eng) << std::endl;  

}

关于random库的更多的内容可参照参考文档,文字太多了我也没仔细看,只是参照别人的代码改了下就拿来用了。

当然,如果你没有使用标准库的习惯的话(其实本人也不是很喜欢用标准库),你也可以利用rand()函数自己生成正态随机数。根据采用的数学原理不同,似乎会用很多种方法。下面的是采用由瑞利分布导出的公式为基础来生成正态随机数的。

double carmen_gaussian_random(double mean, double std)
{
  const double norm = 1.0 / (RAND_MAX + 1.0);
  double u = 1.0 - rand() * norm;                  //u不能为 0 
  double v = rand() * norm;     //由于是伪随机请自行选择seed来保证更真实的随机
  double z = sqrt(-2.0 * log(u)) * cos(2.0 * M_PI * v);
  return mean + std * z;
}

数学原理的描述是这样的:若x1,x2是(0,1)上的均匀分布则y1=(-2ln(x1))^.5cos(2pix2)和y2=(-2ln(x2))^.5sin(2pix1)都是标准正态分布的随机数。