一、伪随机数生成
1. rand()
rand()会返回一个随机数值,范围是在0至RAND_MAX间。RAND_MAX定义在stdlib.h头文件中,其值为2147483647。
2. srand()
srand()可以用来设置rand()产生随机数时的随机数种子。通过设置不同的种子,可以获取不同的随机数序列。例如,可以利用srand(time(nullptr))的方式,根据系统时钟,产生不同的随机数种子。
3. 测试代码 - #include <iostream>
- #include <vector>
- #include <ctime>
- 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 <iostream>
- #include <random>
- 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 <iostream>
- #include <random>
- #include <ctime>
- 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<int> 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 <iostream>
- #include <random>
- #include <ctime>
- 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
复制代码 |