c++进阶STL-随机数

介绍

在新的标准之前,C和C++产生随机数都依赖与简单的C库函数rand(),这个函数产生一个伪随机数均匀分布在[0-system dependent maximum value(at least 32767)]。


但是rand()函数存在问题:有的程序需要不同的随机数范围,有的程序需要浮点随机数,有的程序可能需要的不是均匀分布的随机数。所以在程序员处理、转换这些问题的时候往往可能引入不随机的特性


为了解决这个为题,新的c++库引入随机数库,定义在 <random> 头文件中,主要两个类:

EngineDistribution
生成无符号整型的随机序列利用Engine,根据特定的分布,返回随机数

random-number generator:指的是distribution 的对象关联一个Engine

知识点

库中的Distribution 和 Engine

详见: c++ prime p883-p885

distribution说明
均匀分布**************************
uniform_int_distribution<types> u(m,n)产生[m,n]均匀分布的整数
uniform_real_distribution<types> u(m,n)产生[m,n]默认[0-1]均匀分布的实数
伯努利分布**************************
bernoulli_distribution b( p )
binomial_distribution<types>b(t, p)
geometric_distribution<types> g( p )
negative_binomial_distribution<types> nb(k, p)
泊松分布*************************
poisson_distribution<types> p(x)
exponential_distribution<types> e (lam)
gamma_distribution <types> g(a, b)
weibull_distribution<types> w (a, b)
正态分布*************************
normal_distribution<types> n (m, s)
lognomal_distribution<types> ln (m, s)
chi_squared_distribution<types> c ( x )
cauchy_distribution<types> c (a, b)
fisher_f__distribution<types> f (m, n)
student_t__distribution<types> s( n)
抽样分布*************************
discrete_distribution<types> d( i, j )
discrete__distribution<types> d { il }
piecewise_constant_distribution<types> pc(b, e, w)
piecewise_linear_distribution<types> pl(b, e, w)

Engine说明
default_random_engine
shuffle_order_engine
linear_congruential_engine
mersenne_twister_engine
subtract_with_carry_engine
discard_block_engine
independent_bits_engine

生成随机序列

  • 我们需要注意的是:一个给定的random-number generator每次生成的序列都是一样的(这种情况有时候便于调试),如下代码:
vector<unsigned int > bad_randVec()
{
    default_random_engine e;
    uniform_int_distribution<unsigned int> u(0, 9);
    
    vector<unsigned int> ret;
    
    for(int i=0; i<10; i++)
	ret.push_back(u(e));
    
    return ret;
}

如果想每个调用这个函数每次生成的序列不一样,有两种方案:

  1. (利用static):
vector<unsigned int > bad_randVec()
{
   	static default_random_engine e;
    static uniform_int_distribution<unsigned int> u(0, 9);
    
    vector<unsigned int> ret;
    
    for(int i=0; i<10; i++)
	ret.push_back(u(e));
    
    return ret;
}
  1. 利用seed
  • 手动提供种子
defalut_random_engine e(32767);  //第一种:初始化的时候
e.seed(32767) // 第二种: 初始化之后,调用成员函数

  • 利用time()函数,头文件 <ctime>
defalut_random_engine e(time(0)); 
  • 利用random_device,random_device提供()操作符,用来返回一个min()到max()之间的一个数字.可以理解真随机数
std::random_device rd;
defalut_random_engine e(rd(0)); 

其他类型分布

浮点数分布

以前通常是使用 rand()/RADN_MAX来产生[0 1]的实数均匀分布。但这是不准确的,因为int型相比于浮点数通常是精确度低,所以有的浮点数永远不会生成。

default_random_engine e;
uniform_real_distribution<double> u(0,1);

for(size_t i=0; i<10; i++)
	cout << u(e) << " ";

注意:如果想使用默认的数据类型的分布(通常浮点数:double, 整数:int), 我们传递模板参数为空,如:uniform_real_distribution<> u(0,1)


Normal Distribution

    default_random_engine e;
    normal_distribution<> n(4, 1.5);
    vector<unsigned> vals(9); //记录0-9的每个数字的个数

    for(size_t i=0; i<200; i++)
    {
	unsigned v = lround(n(e));
	if(v< vals.size())
	    ++vals[v];
    }

    for(size_t j=0; j!= vals.size(); ++j)
	cout << j << ": " << string(vals[j], '*') << endl; 


在这里插入图片描述


Bernoulli distribution

这不是一个模板类,是一个普通类,返回总是bool value
举例:假如你和电脑玩游戏,总有一个人先开始,who is first,我们可以通过 uniform_int_distribution<unsigned> (0, 1); 或者可以通过Bernoulli distribution来make a choice。

string resp;
default_random_engine e;
bernoulli_distribution b;  // 默认 返回 true : false = 0.5  : 0.5
//bernoulli_distribution b(0.55); // 返回 true:false = 0.55:0.45

do
{
	bool first = b(e);
	cout << (first ? "computer first" : "you first") << endl;
	cout << (play_game(first) ? "sorry, you lost" : "congratulations, you won" ) << endl;
	cout << "pay again? enter yes or no" << endl;
}while(cin >> resp && resp[0] == 'y')


值得注意的是,我们 declare engine outside of loops,所以每次产生结果不一样,如果在loop内声明的话,每次的结果都是一样的


版权声明:本文为zzyczzyc原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。