C++-随机数的产生
一、随机数
以前学C语言的时候感觉随机数没啥用的,现在想想是自己无知啦,在帮人做一个项目的时候发现随机数还是相当有用的,我们可以利用随机数来生成大量的测试数据。
有两种方法可以让你的程序每次运行结果不同:
1.让用户输入不同的数据(或者从文件中读取不同的数据);
2.对用户输入的相同数据采取不同的处理方式,使其运行结果不同。
大多数情况下,第一种方法是非常好的,用户总是希望他们程序的结果是可预测的。比如当编写一个文本编辑器或者网页浏览器时,你会希望程序在用户每次输入一段文本或网址时执行同样的操作,而不是由浏览器随机决定访问哪个页面,除非是使用StumbleUpon1。
1StumbleUpon是一个能让你“偶遇”有趣网页的网站:http://www.stumbleupon.com/。
但在某些情况,每次执行相同操作并不是一个好的处理方式。例如,很多电脑游戏依赖随机,俄罗斯方块便是一个典型的例子,如果每次游戏方块的下落顺序都相同,用户便会记住下落顺序,因为可以预测接下来会出现什么方块,所以得分会一次比一次高。最后游戏和背诵圆周率的千位小数没啥不同。为了让俄罗斯方块游戏更有意思,程序需要随机选择下一次方块的形状和朝向。
为了实现这个功能,计算机需要生成随机数。因为计算机会准确执行命令,当我们执行相同的操作时计算机总会返回同样的结果。这就很难生成真正的随机数。不过没有必要生成真的随机数。生成像随机数的数也能达到目的,这就是伪随机数。
要生成伪随机数,计算机需要一个种子,利用数学变换将种子转换成另一个值。新值再成为下一个种子。如果程序每次采用不同的种子,程序便永远不会生成相同的数据序列。这里使用的数学转换需要特别挑选,要让所有数字的生成概率相等但又不会有明显的计算模型。(例如,它不会只是每次对数字加1。)
C++提供了所有的功能。你无需关心数学转换,C++中有相关的函数实现。所有你要做的只是提供随机种子,使用当前时间作种子即可。让我们看一下细节:
1.1 随机数的产生
C++有两个函数,一个是设置随机种子,另一个是用种子产生随机数:
1 void srand (int seed);
srand函数将某个数字设置为种子。在程序开头处需要调用一次srand。使用srand的典型方法是把time函数的结果作为参数,time函数返回一个代表当前时间的数值。
time函数返回从1970年1月1日起到现在的秒数。这个规则源自于Unix操作系统,有时它称为Unix time。大多数情况下,时间存储在32位有符号整型中。
随着时间的增加,秒数会超过整型可表示的范围,最后将以负数结尾表示过去的时间。超过整型数的现象将发生在2038年,它引起了对“2038年问题”(Year2038 Problem)的讨论,使用Unix time的计算机程序将会把2038年当做1901年处理。详情请参考:
http://en.wikipedia.org/wiki/Year_2038_problem。
1 srand ( time ( NULL ) );
目前你不用了解NULL参数,先就照着这么写;
如果连续调用srand,程序会反复地更新随机数发生器种子,因为连续调用的时间序列非常相近,生成的随机数也会很相近。(使用srand必须包含cstdlib头文件,使用time函数必须包含ctime头文件。
1 #include <cstdlib> 2 #include <ctime> 3 int main () 4 { 5 //在最开始处调用一次 6 srand( time( NULL ) ); 7 }
参照下面原型调用rand函数来获取随机数。
1 int rand ();
注意rand函数没有任何参数,仅有一个返回值。让我们将返回值输出出来。
1 #include <cstdlib> 2 #include <ctime> 3 #include <iostream> 4 using namespace std; 5 int main () 6 { 7 //在最开始处调用一次 8 srand( time( NULL ) ); 9 cout << rand() << '\n'; 10 }
C++有一个返回除法余数的操作符(如4/3商为1,余数为1)——模数运算符。如果你没有注意到也不要紧,人们总是自动屏蔽数学函数。但模数非常有用。因为被4整除的余数的范围是0~3。如果用rand函数返回的随机数除以所需数字的范围长度(即范围内数的数量),便会获得0到最大范围之间的值(不包含最大值)。
1 #include <ctime> 2 #include <cstdlib> 3 #include <iostream> 4 using namespace std; 5 int randRange (int low, int high) 6 { 7 //先获取随机数,再处理得到从0到所需数字范围长度的值,然后加上最小值 8 return rand() % ( high - low + 1 ) + low; 9 } 10 int main () 11 { 12 srand( time( NULL ) ); 13 for ( int i = 0; i < 1000; ++i ) 14 { 15 cout << randRange( 4, 10 ) << '\n'; 16 } 17 }
这段程序有两点需要注意的地方。首先,我们必须对high-low加1,举例说明原因,设想目标范围是0到10,当中有11种可能出现的值。减法获得的是两个值之间的差值,比范围内值的数量少1,因此必须加1。其次,注意我们需要加上目标范围的最小值,设想如果想获取10到20之间的数,通过上面的方法只能获取0到10之间的随机数,再加10才能将范围设定到10到20之间。
参考文献:c++现代程序设计方法
小结:
-我们产生随机数不用自己去编写数学变换公式,直接调用两个随机函数
-time(NULL)返回当前距离1970年的秒数,将其作为参数传递给srand生成随机种子;
-rand()生成随机数,无形参,每调用一次返回值一个