【C/C++】随机函数rand()和初始化随机函数srand()

668 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情


随机函数 rand()

首先明确计算机中没有真正的随机函数,而这些所谓的随机函数都是伪随机。

伪随机: 如果我们不改变随机函数的种子(这里的种子可以理解为随机函数的初始值),那么随机数的数序也不会改变,使用相同的随机函数种子每次我们都将得到同一组数序的随机数,这就是伪随机。(皇室战争手游中宝箱的获取就是伪随机)

rand() 函数定义

  • 头文件:在C中为 #include<stdlib.h> ;C++中为 #include<cstdlib>,包含在 #include<iostream>
  • 函数方法:int rand(void);
  • 功能:无需函数参数,返回随机数范围 [0, RAND_MAX) 左闭右开区间,RAND_MAX 根据不同系统值不同。RAND_MAX 最小值为32767327670x7fff),最大值为21474836472147483647INT_MAX
  • 若未调用初始化随机函数 srand() ,系统会自动调用一次初始化随机函数 srand(1)

rand() 常用操作

  • rand() % x : 得到 [0,x)[0,x) 左闭右开区间内的一个随机数
  • (rand() % 10) / (double)9 : 得到 [0,1][0,1] 区间内的一个随机小数(概率0%-100%
  • a + rand() % b :得到 [a,a+b)[a,a+b) 左闭右开区间内的一个随机数

初始化随机函数 srand()

想要得到更进一步的随机数,就需要用到初始化随机函数 srand()

srand() 函数定义

  • 头文件与 rand() 一致:在C中为 #include<stdlib.h> ;C++中为 #include<cstdlib> 包含在 #include<iostream>
  • 函数方法:void srand(unsigned int seed);
  • 功能:初始化 rand() 函数的随机种子

如果每次使用相同数值的种子进行初始化,rand() 函数也将会产生同一组随机数值。例如我们每次都不调用 srand() 函数,那么系统每次都会自动调用一次初始化随机函数 srand(1),也就是每次的初始化随机函数种子为 1 ,那么我们每次使用的随机数值都是同一组。

srand() 常用的初始化随机函数操作

  • 使用当前系统时间作为种子进行随机数发生器的初始化:因为每次调用 srand() 函数的时间通常是不同的(运行时间需要间隔超过 1 秒),这样就可以保证每次的 rand() 函数产生的随机数值具有随机性了。
srand((unsigned)time(NULL));//time(NULL)也可以写成time(0)

调用 time(NULL) 的返回值(类型为 time_t )显式强转型成 unsigned int ,再传递给 srand() 函数(接收一个 unsigned int 参数)作为种子进行初始化随机函数。

关于 time() 函数

time() 函数是C标准库函数。

  • 头文件:在C中需要添加头文件 #include<time.h> ,C++中需要添加头文件 #include<ctime>
  • 函数方法原形:time_t time(time_t *t) (其中 time_t 就是 long int
  • 函数功能:这里的 time() 函数如果传入的参数为 NULL 或者 0 ,返回的是从 00:00:00 GMT, January 1, 1970 到现在所持续的秒数。
#include<bits/stdc++.h>
using namespace std;
int main(){
	time_t t;
	t = time(0);//同time(NULL)
	printf("秒数为:%ld\n",t);
	printf("当前时间:%s", ctime(&t));
	return 0;
}
/*
运行结果:
秒数为:1649932240
当前时间:Thu Apr 14 18:30:40 2022
*/

time(0)time(NULL) 函数可以获取当前的系统时间(但是获取的这个时间是从1970年1月1日0时0分0秒到目前为止所经过的秒数),ctime() 函数可以将 time_t* 类型转化为常规的时间格式,并且以字符数组类型作为返回值。char* ctime (const time_t *time)ctime 返回的是字符数组(字符串)类型。

随机函数的使用

蓄水池抽样算法

从前往后处理每个样本,每个样本成为答案的概率为 1/i,这样就能使得每个样本抽到的概率相同为 1/n 使得每个概率为 1/i 的做法:rand() % i == 0

代码部分

srand((unsigned)time(NULL));
int idx = 0;//开始只有一个,初始化idx为第一个下标
//随机抽取下标,范围在[0, n),左闭右开区间,%的数代表前面的个数
for(int i = 1; i < n; i++){
    if(rand() % (i + 1) == 0) idx = i;
}

总结

计算机中没有真正的随机函数,也不能真正的产生随机数,但计算机中存在伪随机数序,我们利用伪随机数序和当前系统时间相结合,使用系统当前时间(时间是不断改变的)作为伪随机数序的随机种子,使得我们得到的数序能够更具有随机性。所以我们在使用 rand() 函数前通常都会先初始化随机函数,为了使得随机函数得到的数序不是同一段数序,初始化随机函数的种子也要更具有随机性,所以我们采用系统当前的时间作为初始化随机函数的种子。这就是我们常用的操作手法:srand((unsigned)time(NULL));


结束语

生活是一场充满未知的旅途。不要因为眼前的困境,就丧失对未来的期盼。以积极的心态,活出最佳状态,便是交给生活最好的答卷。心中有光,有所热爱。请相信,那些不期而遇的幸运,正在朝你奔来。