函数库:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
主要函数(两个):
void srand (unsigned int seed) //改变rand函数中的种子
int rand(void) //在对应的种子中取数
rand函数的内部实现是使用的线性同余法,产生出来的随机数是伪随机数(利用linear congruential generator作为生成器来生成伪随机数),但是我们可以采取一定的方法来实现以假乱真的效果。
我们在学习时不需要考虑两个函数的原理,只去想他的作用就可以了,因此具体原理不做详细解释。
我们直接以实例来进行解释,最终达到能够使用的目的即可:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
srand((unsigned int)time(NULL));
int a = rand() % 50 + 1;
printf("%d\n",a);
return 0;
}
首先进行一下知识补充:
time(NULL)作用:取系统中的时间,精确到秒。 //这是为了不熟悉<time.h>函数库的同学准备的。
我们可以将 rand 函数想象成从一个罐子里抓球的行为。
int a = rand() % 50 + 1;
//在罐子中抓取一个球,对这个球的编号取余50,然后加1。
//其实只在程序中输入int a = rand()就可以运行,而在后面取余的目的是为了确定这个随机
//数的范围。
//我们知道,任何一个数x,取余后的得数都是0到x-1,因此我们可以使用这个特性来确定一
//个数的范围,上例所示的范围为[1,50],如果不加1,范围则是[0,49]
每次抓出的球都是随机的。但是,如果只使用rand这一个函数(将上面的代码放入编译器环境,注释掉第5行试试)的话,你会发现每次系统输出的值是一样的。这是为什么呢?
{ 42 },假设左边的集合对应一个罐子,如果其中只有一个球42,那么你每次抓出的球都是一样的,现在的rand函数就是对应的这种情况。
原因就是:rand函数不会自己去改变所抓的罐子,而这个改变罐子的操作就需要由srand函数来承担。
这个时候需要在rand函数 前 添加这样一行函数:
srand((unsigned int)time(NULL));
什么意思呢?
读取系统中的时间作为编号,将罐子替换为对应的编号。
这个编号为无符号整形。
通过rand函数和srand函数的相互配合最终达到生成伪随机数的目的。
整个随机数从生成到输出的过程实际上是这样的:
1.srand函数读取系统时间,即挑选罐子。
2.rand函数在罐子中抓取对应编号的球。
3.对编号进行处理,框定一个范围。
4.打印出对应数字。
从上面的示例可以看出,系统中似乎无形之中存在着一个罐子。这个罐子是什么呢?
罐子实际上就是一个种子,每个种子对应一串序列,序列中存放着不同的数字,这些种子是一开始就被存放进编译器中的,序列值会根据编译环境的不同而不同。
rand函数就像播种,当你的种子不变时,所生长出的作物也是不变的,因此会产生同一个数。
这时侯你可能会有一个问题:如果不调用srand函数选罐子的话,那么每次都输出相同的数,难道罐子中只有一个数字吗?
当然不是。请看下面这段代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(1);
int a = rand() % 10;
int b = rand() % 10;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
输出结果:
1
7
//无论运行多少次都是这样的结果。
这里和在罐子中取数的情况不同了。刚刚说了,每个种子代表一个序列。而系统每次取在对应种子中取数时,都是从序列的第一个值开始,因此如果执行两次rand函数的话,则会取出种子1所对应序列的前两个值。而这两个值分别对应的数为1和7。
接下来为了便于同学们的使用,我们来介绍几种常见的使用方法:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
void tex_1() {
srand((unsigned)time(NULL));
int a = rand() % 50;//[0,49]
printf("%d\n", a);
return;
}//直接取余
void tex_2() {
srand((unsigned)time(NULL));
int a = rand() % 50 + 1;//[1,50]
printf("%d\n", a);
return;
}//取余+
void tex_3() {
srand((unsigned)time(NULL));
int a = rand() % 50 * 3;//随机可被3整除的数,小于50
printf("%d\n", a);
return;
}//可整除数
void tex_4() {
srand((unsigned)getpid(NULL));//读取进程识别码
int a = rand() % 50;
printf("%d\n", a);
return;
}
int main() {
tex_1();
tex_2();
tex_3();
tex_4();
return 0;
}
1、2、3程序相信各位读者都能理解,但是第4个程序务必需要做一下解释。
上文中提到了rand函数生成的是伪随机数,其随机性是由时间所对应的种子编号决定的。因此,如果你多运行几次程序的话会发现:产生的随机数有时候会有一个增大或变小的趋势。
那么如何避免这种情况呢?
我们可以换一个产生种子的方式:
getpid(NULL) //获取当前程序的进程码
每个程序的进程码是不一样的,因此可以以此来当作种子的随机产生方式。
其实通过srand的随机数生成还可以用来随机一个事件并确定结果概率,(通过swich函数)这里不做详细介绍。