C++随机数发生器。
Update
c++11中提供了一种新的产生随机数的方式:
1 |
|
参考链接
Generating random numbers in C++
以下为原答案
rand()
生成随机整数的核心函数是cstdlib
中的rand()
,它生成一个闭区间 [0, RAND_MAX] 内的均匀随机数(均匀的含义是:该区间内每个整数被随机获取的概率相同),其中RAND_MAX
是定义在cstdlib中的一个宏变量,在不同环境下的值可能不同,但是保证至少为$32767(2^{15} - 1)$。
严格地说,这里的随机数是“伪随机数”,因为它也是由数学公式计算出来的,不过在算法领域,多数情况下可以把它当作真正的随机数。
产生[0, n]之间的整数
可以用rand() % n
的方式产生区间 $[0, n - 1]$ 内的一个随机整数。但是一方面这会破坏产生的整数分布的均匀性,另一方面只要n
大于 RAND_MAX
这种方法就不能得到期望的结果。由于RAND_MAX
可能只有 32767 这么小,所以在使用这种方法的时候要小心。
另一个方法是执行rand()
后先除以RAND_MAX
,得到 $[0, 1]$ 之间的随机实数,扩大n
倍后四舍五入,得到 $[0, n]$ 之间的均匀整数。
具体用法
需要随机数的程序在最开始时一般会执行一次srand(time(NULL))
,目的是初始化“随机数种子”。简单来说,种子是生成随机数的计算依据。种子相同,计算出来的“随机数”序列总是相同。譬如运行下面的程序:
1 |
|
可以得到这样的一组随机数:
1 | 677741240 |
但是当我们第二次运行这段代码的时候,我们会得到相同的一组随机数,原因就在于,我们每次运行时srand
函数中初始化的种子始终是100
。
而当我们使用srand(time(NULL))
来替代上面的srand(100)
时,由于time()
函数会返回系统当前时间,所以每次运行程序时这个值都会不一样,也就使得每次运行生成的随机数序列不同。
如果不调用srand
而直接使用rand()
,相当于调用过一次srand(1)
。
另外,不要在同一个程序每次生成随机数之前都重新调用一次srand。譬如运行下面的程序:
1 |
|
会发现生成的三个随机数是相同的(随机数的具体值因人而异):
1 | 805428961 |
仔细思考一下就很可以分析出原因:生成随机数的序列是由“种子”决定的,在这段代码里的种子就是time(NULL)
的返回值了,也就是系统当前时间(准确来说是自UTC时间1970年1月1日0点依赖经过的“秒数”),它每秒变化一次,但是程序在上面三次运行的时间间隔过短,应该毫秒甚至微秒级的,因此上面三个随机数是同一个种子生成的,而且因为每次都被重新初始化,所以都是同一个随机数序列的第一个值。
“同一套随机数”可能是好事也可能是坏事。例如,若要反复测试程序对不同随机数据的响应,需要每次得到的随机数不同。另一方面,如果发现某一程序对于一组随机数据报错,就需要在调试时“重现”这组数据。另外,不同的编译器计算随机数的方法可能不同。如果是不同编译器编译出来的程序,即使是用相同参数调用srand()
,也可能的都不同的随机序列。
参考
主要参考了刘汝佳老师的《算法竞赛入门经典》(第2版)第五章中5.2.6-测试STL一节中的内容。