一、伪随机数生成
1. rand()
rand()会返回一个随机数值,范围是在0至rand_max间。rand_max定义在stdlib.h头文件中,其值为2147483647。
2. srand()
srand()可以用来设置rand()产生随机数时的随机数种子。通过设置不同的种子,可以获取不同的随机数序列。例如,可以利用srand(time(nullptr))的方式,根据系统时钟,产生不同的随机数种子。
3. 测试代码
#include
#include
#include
int main(int argc, char** argv){
// 生成rand()的随机数种子
srand(time(nullptr));
for (int i = 0; i < 100; i){
// 用rand()产生随机数
std::cout << rand() << std::endl;
std::cout << rand()/(rand_max * 1.f) << std::endl;
}
return 0;
}
备注: 随机数生成的范围:
1) [0, n),即rand() % n;
2) [a, b),即rand() % (b - a) a;
3) [a, b],即rand() % (b - a 1) a;
4) (a, b],即rand() % (b - a) a 1。
5) a rand() % n,[a, a n);
6) [0 , 1)之间的浮点数,rand()/(rand_max * 1.f)
二、c 11随机数生成
1. 随机数生成算法
相对于rand()和srand()生成伪随机数的方式来说,c 11的随机数生成器更加复杂,主要是因为在c 11中提供了比较多的选择方式
c 11随机数生成方式有:
1) linear_congruential_engine 线性同余随机数引擎
2) mersenne_twister_engine 梅森旋转随机数引擎
3) subtract_with_carry_engine 带进位随机数引擎
上面的三种随机数生成算法均是模板类,需要我们自己进行实例化;模板类实例化需要的参数,均是算法中使用的参数,若是不懂其原理,建议不要使用这些模板类,因为我们不清楚用什么样的参数才能得到较好的随机序列。不过不用担心,在c 11标准中,已经帮我们预先定义了一些随机数类,它们都是用过上面的三个类模板实例化出来的。
类名称 | 属性 | 依赖类 |
---|---|---|
linear_congruential_engine | templates | \ |
mersenne_twister_engine | templates | \ |
subtract_with_carry_engine | templates | \ |
discard_block_engine | engine adaptors | \ |
independent_bits_engine | engine adaptors | \ |
shuffle_order_engine | engine adaptors | \ |
default_random_engine | instantiations | 待定 |
minstd_rand | instantiations | linear_congruential_engine |
minstd_rand0 | instantiations | linear_congruential_engine |
mt19937 | instantiations | mersenne_twister_engine |
mt19937_64 | instantiations | mersenne_twister_engine |
ranlux24_base | instantiations | subtract_with_carry_engine |
ranlux48_base | instantiations | subtract_with_carry_engine |
ranlux24 | instantiations | ranlux24_base、discard_block_engine |
ranlux48 | instantiations | ranlux48_base、discard_block_engine |
knuth_b | instantiations | shuffle_order_engine |
从上表中可以看出,在依赖类(第三列)中有一个”待定“,它的类是default_random_engine;它也是一个实例化的类。它的实现会和编译器有很大的关系,有的编译可能会用linear_congruential_engine,也可能会用mersenne_twister_engine。代码如下所示:
#include
#include
int main(int argc, char**argv){
std::default_random_engine engine;
for (int i = 0; i < 10; i ){
std::cout << engine() << " ";
}
std::cout << std::endl;
return 0;
}
2. 随机数分布类型
- 均匀分布
uniform_int_distribution 整数均匀分布
uniform_real_distribution 浮点数均匀分布 - 伯努利类型分布
bernoulli_distribution 伯努利分布
binomial_distribution 二项分布
geometric_distribution 几何分布
negative_binomial_distribution 负二项分布 - rate-based 分布
poisson_distribution 泊松分布
exponential_distribution 指数分布
gamma_distribution 伽马分布
weibull_distribution 威布尔分布
extreme_value_distribution 极值分布 - 正态分布
normal_distribution 正态分布
lognormal_distribution 对数正态分布
chi_squared_distribution 卡方分布
cauchy_distribution 柯西分布
fisher_f_distribution 费歇尔f分布
student_t_distribution t分布 - 分段分布
discrete_distribution 离散分布
piecewise_constant_distribution 分段常数分布
piecewise_linear_distribution 分段线性分布 - 其它
seed_seq 种子序列
generate_canonical 生成归一化
#include
#include
#include
int main(int argc, char**argv){
const int nrolls = 10000;
const int nstars = 100;
std::minstd_rand engine1(time(nullptr));
int param = 10;
std::poisson_distribution distribution(param);
int p[20] = {
};
for(int i = 0; i < nrolls; i){
int tmp = distribution(engine1);
if (20 > tmp) {
p[tmp];
}
}
std::cout << "poisson_distribution param: " << param << std::endl;
for (int i = 0; i < 20; i){
std::cout << i << ": " << std::string(p[i] * nstars/nrolls, '*') << std::endl;
}
return 0;
}
result:
poisson_distribution param: 10
0:
1:
2:
3:
4: *
5: ***
6: ******
7: ********
8: ***********
9: ************
10: ************
11: ***********
12: **********
13: *******
14: *****
15: ***
16: **
17: *
18:
19:
3. random_device
random_device是标准库提供的一个非确定性随机数生成设备,是所有生成器中唯一一个不需要随机数种子的方式。在linux中,是需要读取/dev/urandom设备。需要注意的是random_device在某些操作系统中是无法使用的,会在构造函数或者调用operator()函数时抛出异常,因此在进行代码移植时,需要格外注意。
// random_device 说明
// random_device::min() --- 范围最小值
// random_device::max() --- 范围最大值
// operator() --- 生成一个随机数
// entropy() --- 计算operator()调用生成的随机数的熵,如果random库使用随机数引擎(即伪随机数算法)实现而不是真随机数生成器,那么该值为0
#include
#include
#include
int main(int argc, char**argv){
std::random_device rd;
std::cout << "range: " << rd.min() << '\t' << rd.max() << std::endl;
std::cout << "random1: " << rd() << std::endl;
std::cout << "random2: " << rd() << std::endl;
std::cout << "random3: " << rd() << std::endl;
std::cout << "entropy: " << rd.entropy() << std::endl;
return 0;
}
result:
range: 0 4294967295
random1: 2104889535
random2: 1299396987
random3: 1841354037
entropy: 0