C++为随机数提供了两套工具:C风格的和C++风格的。ios
C为随机数提供的工具是rand
、srand
和RAND_MAX
,定义在<stdlib.h>
中。dom
srand
为rand
设置种子,若是不设置,至关于调用过srand(1)
。rand
产生伪随机数,其范围为0
到RAND_MAX
,RAND_MAX
至少是32767
,在MSVC和GCC中这个值都是32767
。函数
伪随机数看似随机,实则是有规律可循的,对于相同的种子值,rand
产生的序列彻底相同,也就是说不管你给srand
一个什么数字,屡次运行程序的结果都将相同——除非你给srand
的是不一样的数字,好比时间。<time.h>
中的time
函数返回整数表示的系统时间,可用于设置种子。工具
若是咱们只须要0
到9
的随机数,能够把rand
的返回值% 10
;若是是42
到233
,能够写rand() % 192 + 42
。下面的random
函数封装了这项工做。注意只有在b - a + 1
远小于或整除RAND_MAX
时随机数的分布才比较均匀。性能
#include <stdio.h> #include <stdlib.h> #include <time.h> int random(int a, int b) { return rand() % (b - a + 1) + a; } int main() { srand(time(NULL)); printf("RAND_MAX = %d\n", RAND_MAX); for (int i = 0; i < 10; i++) printf("%d ", rand()); printf("\n"); int count[10] = {0}; for (int i = 0; i < 10000; i++) count[random(0, 9)]++; for (int i = 0; i < 10; i++) { printf("%d: ", i); for (int j = 0; j < count[i] / 10; j++) printf("*"); printf("\n"); } }
从C++11开始,C++标准规定了随机数设施,包括均匀随机位生成器(Uniform random bit generators,URBG)和随机数分布等,定义在<random>
中。code
URBG分为随机数引擎、引擎适配器、预置随机数生成器和非肯定随机数生成器4类,一般后两类就够用了。orm
标准规定了3种随机数引擎:内存
线性同余linear_congruential_engine
(LCG),时间空间消耗都少;开发
梅森旋转mersenne_twister_engine
(MT),占用较多内存(在PC上能够忽略),计算量较大;rem
带进位减法(属于滞后斐波那契生成器,LFG)subtract_with_carry_engine
,性能与效果折中。
随机数引擎都须要一个种子,生成的都是伪随机数。
引擎适配器能够套一个随机数引擎:
discard_block_engine
在连续若干个伪随机数中选择若干个;
independent_bits_engine
把位数多的伪随机数压缩成位数少的;
shuffle_order_engine
把连续若干个伪随机数重排。
套娃的方式是模板,理论上你还能够用适配器套适配器,不过CPU可能会有意见。
随机数引擎的模板参数怎么取?标准定义了一些数学家们发现的效果良好的随机数引擎:LCG minstd_rand0
、minstd_rand
、knuth_b
;MT mt19937
、mt19937_64
;LFG ranlux24_base
、ranlux48_base
、ranlux24
、ranlux48
。若是你仍是无从下手,那就用default_random_engine
,编译器的开发者们为你选好了他们认为最合适的,在MSVC中是mt19937
,在GCC中是minstd_rand0
。
以上工具都生成伪随机数,标准还定义了真·随机数引擎random_device
,尽管标准也容许它是伪随机的。若是它是真随机的,那么使用起来它的效果无疑是最好的,可是屡次调用后性能会急剧降低,一般只用于生成伪随机数引擎的种子。
随机数生成器类型都定义了静态方法min
和max
,返回生成的随机数的范围,以及无参数的函数调用运算符operator()
,返回随机数。
#include <iostream> #include <random> int main() { auto engine = std::default_random_engine(std::random_device()()); std::cout << "min = " << engine.min() << "; max = " << engine.max() << std::endl; std::cout << "random numbers: "; for (int i = 0; i != 10; ++i) std::cout << engine() << ' '; std::cout << std::endl; }
大多数状况下咱们不须要min
到max
范围的整数,而须要必定分布的整数或实数。标准规定了许多随机数分布类型,我数学很差,不太懂这些。
均匀分布uniform_int_distribution
、uniform_real_distribution
;
伯努利分布bernoulli_distribution
、binomial_distribution
、negative_binomial_distribution
、geometric_distribution
;
泊松分布poisson_distribution
、exponential_distribution
、gamma_distribution
、weibull_distribution
、extreme_value_distribution
;
正态分布normal_distribution
、lognormal_distribution
、chi_squared_distribution
、cauchy_distribution
、fisher_f_distribution
、student_t_distribution
;
抽样分布discrete_distribution
、piecewise_constant_distribution
、piecewise_linear_distribution
。
构造分布实例时传入分布的参数。调用operator()
得到结果,参数为随机数引擎。
#include <iostream> #include <random> #include <string> int main() { auto engine = std::default_random_engine(std::random_device()()); std::uniform_int_distribution<int> uniform(0, 9); int count[10] = {0}; for (int i = 0; i != 10000; ++i) ++count[uniform(engine)]; for (int i = 0; i != 10; ++i) std::cout << i << ": " << std::string(count[i] / 10, '*') << std::endl; }
注意,与STL中左闭右开的习惯不一样,uniform_int_distribution
构造函数接受的参数是闭区间。