C++随机数产生以及通过Eigen库获得正态分布的随机矩阵

简介

在C++11标准之前,一般是利用rand()函数产生一个均匀分布的,范围从0到系统相关的最大值之间的随机整数,然后再通过转换得到不同分布的随机数,这种方法比较麻烦,同时转换过程中会引入非随机性。

C++11标准中,定义了随机数引擎类随机数分布类,通过随机数引擎和随机数分布的组合,可以产生各种分布的随机数。这些类包含在头文件random中,使用前需要先包含random头文件:

#include<random>

随机数产生

随机数引擎和随机数分布都是重载了调用运算符"()"的函数对象类,随机数引擎的调用运算符不接受参数,并且返回一个unsigned随机数,称为原始随机数。而随机数分布的调用运算符接受一个随机数引擎类作为参数,返回服从特定分布的随机数。

1 随机数引擎
一般采用default_random_engine类创建一个随机数引擎对象(default_random_engine的具体实现与不同的编译器有关)。创建随机数引擎的方式如下
default_random_engine e;

2 随机数分布
随机数服从的分布由随机数分布类决定,如

分布类型 随机数分布类
正态分布 normal_distribution<RealT> n(m,s) 均值为m,标准差为s,m默认值为0,s默认值为1
χ 2 \chi^2 χ2分布 chi_squared_distribution<RealT> c(x) x为自由度,默认为1.0
T分布 student_t_distribution<RealT> s(n) n为自由度,默认为1

3 利用随机数分布和引擎产生随机数
以正态分布为例,下面的例子产生一个服从 N ( 0 , 1 0 2 ) N(0,10^2) N(0,102)(即均值0,标准差10的正态分布)的随机数。

#include<iostream>
#include<random>
#include<ctime>
using namespace std;
int main(){
    
    
  //产生随机数引擎,采用time作为种子,以确保每次运行程序都会得到不同的结果
  static default_random_engine e(time(0));
  //产生正态分布对象
  static normal_distribution<double> n(0,10);
  double random_number=n(e);//把引擎作为参数,调用随机分布对象
  cout<<random_number<<endl;
  return 0
}

最好把引擎和分布都定义为static。

使用Eigen库和C++随机数机制,产生正态分布的随机矩阵

Eigen中只有产生均匀分布随机矩阵的Random(),没有其他分布类型的随机矩阵函数。

借助Eigen提供的unaryExpr函数,可以对矩阵的每一个元素进行同一个操作。unaryExpr接受一个函数对象作为参数,该函数对象定义了所要对元素进行的运算。因此,我们只需要定一个产生随机数的函数对象,将其作为参数传给unaryExpr,即可对矩阵每一个元素产生随机数。可以用lambda表达式作为函数对象,也可以定义一个函数,并用ptr_fun()函数将函数指针转成函数对象。下面给出这两种方式的实现。

1 采用lambda表达式

#include<iostream>
#include<random>
#include<Eigen/Eigen>
#include<ctime>
using namespace std;
using namespace Eigen;

int main(){
    
    
  static default_random_engine e(time(0));
  static normal_distribution<double> n(0,10);
  MatrixXd m=MatrixXd::Zero(10,10).unaryExpr([](double dummy){
    
    return n(e);});
  cout<<"Gaussian random matrix:\n"<<m<<endl;
  cout<<"Mean: "<<m.mean()<<endl;
  MatrixXd m2=(m.array()-m.mean())*(m.array()-m.mean());
  cout<<"std: "<<sqrt(m2.sum()/(m2.size()-1))<<endl;
}

2 采用ptr_fun将函数指针转成函数对象

#include<iostream>
#include<random>
#include<Eigen/Eigen>
#include<ctime>
using namespace std;
using namespace Eigen;

double generate_random(double dummy){
    
    
  static default_random_engine e(time(0));
  static normal_distribution<double> n(0,10);
  return n(e);
}

int main(){
    
    
  MatrixXd m=MatrixXd::Zero(10,10).unaryExpr(ptr_fun(generate_random));
  cout<<"Gaussian random matrix:\n"<<m<<endl;
  cout<<"Mean: "<<m.mean()<<endl;
  MatrixXd m2=(m.array()-m.mean())*(m.array()-m.mean());
  cout<<"std: "<<sqrt(m2.sum()/(m2.size()-1))<<endl;
}

3 采用原始的二重for循环
当然也可以遍历矩阵的每一个元素,并用随机数给每个元素赋值,这种做法简单暴力

猜你喜欢

转载自blog.csdn.net/X_And_Y/article/details/83414387