c语言 使用rand和srand函数进行随机数的生成,几种常见的用法介绍

函数库:

#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函数)这里不做详细介绍。

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若亦_Royi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值