C++随机数简介

C Random

C接口中提供的随机数接口为rand(),该随机数接口产生0 ~ RAND_MAX范围内的均匀分布的整数,其中RAND_MAX为32767。通常我们可以用rand()接口产生多种随机数:

srand(time(NULL)); // 设置随机数种子
rand(); // 随机unsigned short 
a + rand() % (b - a); // [a, b]范围内的整数
a + rand() / RAND_MAX; // [a, a + 1]范围内的小数
rand() * (1<<16)  + rand(); // [0, (1<<32) - 1)的数

值得一提的是,rand()接口并没有我们想象的那样好用,根据视频rand()的问题[1],C库随机数生成的缺点有:

  • rand()生成的随机数范围有限,srand(seed)接受的种子范围有限
  • rand接口产生的随机数质量较低
  • 使用rand() % n来产生一定范围的数并不是均匀分布,因为不存在一个映射能将32767个值均匀映射到 n个值。
C++ Random

幸运的是,在C++的STL中提供了随机数质量更高,功能更强大的随机数生成器和分布器[2],我们只需要增加<random>头文件即可。在进入使用C++随机数生成器之前,我们首先需要区分随机数生成器和分布器。

  • 生成器:随机数生成器使用一个随机数种子产生伪随机数。依据所采用的随机数生成算法,随机数成器大致分为三类:线性同余算法,梅森缠绕器算法,带进位减算法。

  • 分布器:随机数分布器处理随机数生成器产生的随机数,使其满足一定概率分布。根据其概率分布不同,主要分为:均匀分布,伯努利分布,泊松分布,正态分布,采样分布。详情参见随机数分布

C++ STL中提供了预定义的随机数生成器非确定的随机数生成器预定义的随机数生成器定义了数个特别流行的算法,是较为良好的伪随机数生成接口,其中默认的随机数生成器为std::default_random_engine非确定随机数生成器则使用硬件作为随机数来源,类型为std::random_device。random_device由于调用代价较高,通常用来产生随机数种子。注意若不存在相应硬件,则每次调用产生的随机数序列均一致。

接口使用

通过上面的介绍,我们大致了解了C++随机数库的内容,接下来我们尝试提供基本场景的随机数生成的例子。

//如果有硬件熵源:产生硬件随机种子
std::random_device rd;
unsigned int seed = rd();
//替代方案:使用时间产生随机种子
unsigned int seed = time(NULL);

//使用种子产生随机数生成器: 下面给出了4种,可按喜好挑选。
std::default_random_engine e1(seed); 
// std::minstd_rand e2(seed);
// std::mt19937 e3(seed);
// std::ranlux48 e4(seed); 

//使用随机数生成器产生均匀分布随机数, 同样不能像rand() % n方式产生范围内均匀分布的随机数,故一般不使用
//unsigned int rand_num = e1();

//产生一定范围的随机整数
std::uniform_int_distribution<int> uniform_dist(0, 99);
int rand_int = uniform_dist(e1); //产生一个0-99的随机整数,均匀分布

//产生一定范围的随机实数
std::uniform_real_distribution<> uniform_dist2(0, 1);
float rand_real = uniform_dist2(e1); //产生一个0-1的实数,均匀分布
    
//产生一个正态分布: 均值为0,方差为2
std::normal_distribution<> normal_dist(0, 2);
float sample = normal_dist(e1); //产生一个正态分布的样本

故为了产生可用的随机数,我们至少得执行两行代码准备随机数生成器和分布器,随后调用对应的接口即可生成随机数序列。

std::default_random_engine e1(time(NULL));
std::uniform_int_distribution<int> dist(0, n);

这比传统C库的随机数生成稍微麻烦了一些:C库的随机数种子只需设置一次,即可在任何作用域调用rand()产生随机数。在C++中随机数生成器和分布器仅在相应作用域内可用。

参考文献

[1]. Avoid Using rand() and srand(), https://stackoverflow.com/questions/18726102/what-difference-between-rand-and-random-functions 2020,2,19

[2]. Pseudo-random Number Generation, https://en.cppreference.com/w/cpp/numeric/random 2020,2,19

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值