Skip to content

LV015-随机数

本文主要是用Linux系统中获取随机数的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

一、随机数

在很多时候我们都有可能会用到随机数,就自己一个一个写吗?不可能的,这辈子都不可能自己写的,哈哈。

1. 伪随机数?

随机数是随机出现,没有任何规律的一组数列。在我们编程当中,是没有办法获得真正意义上的随机数列的,这是一种理想的情况,在我们的程序当中想要使用随机数列,只能通过算法得到一个伪随机数序列,那在编程当中说到的随机数,基本都是指伪随机数。

2. rand() 函数

2.1 函数说明

linux下可以使用man 3 rand命令查看该函数的帮助手册。

c
/* 需包含的头文件 */
#include <stdlib.h>
    
/* 函数声明 */
int rand(void);

函数说明】该函数用于获取一个随机数,多次调用可以得到一组随机数序列。

函数参数none

返回值int类型,返回一个介于0RAND_MAX(包含)之间的值,也就是闭区间上的[0, RAND_MAX]。我在Ubuntu 21.0464位版本上试了一下,这个RAND_MAX值是2147483647

使用格式】一般情况下基本使用格式如下:

c
/* 需要包含的头文件 */
#include <stdlib.h>

/* 至少应该有的语句 */
int a;
a = rand();

注意事项

(1)调用rand()可以得到[0, RAND_MAX]之间的伪随机数,多次调用rand()便可以生成一组伪随机数序列,但是需要注意,就是每一次运行程序所得到的随机数序列都是相同的

(2)这里需要提到一个叫做种子的概念,rand()函数通过种子生成随机数序列,当种子相同时,生成的随机数是相同的,当我们没有使用设置中子的函数(srand())时,也就是说如果没有提供种子值,rand()函数将自动以1作为种子值,所以每次程序运行产生的随机数序列都是一样的。

2.2 使用实例

c
#include <stdio.h>
#include <stdlib.h>

int main(int arc, char *argv[])
{
	int i = 0;
	/* 打印随机数序列 */
	printf("[");
	for (i = 0; i < 8; i++)
	{
		printf("%d", rand() % 100);
		if (i != 8 - 1) 
			printf(", ");
	}
	printf("]\n");
	return 0;
}

在终端执行以下命令编译程序:

shell
gcc test.c -Wall # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

shell
[83, 86, 77, 15, 93, 35, 86, 92]

我们多运行几次,就会发现,产生的随机数永远都是这几个,也就是每个程序每次运行的时候得到的随机数都是一样的。

3. srand() 函数

3.1 函数说明

linux下可以使用man 3 srand命令查看该函数的帮助手册。

c
/* 需包含的头文件 */
#include <stdlib.h>

/* 函数声明 */
void srand(unsigned int seed);

函数说明】该函数并不是用于生成随机数,srand()函数将其参数设置为rand()返回的伪随机整数新序列的种子。通过使用相同的种子值调用srand(),也可以得到相同的伪随机数序列。

函数参数

  • seedunsigned int类型,作为产生随机数的种子,一般参数会设置为日历时间,就是通过time()函数获取的秒数,这样可以保证每次程序的运行所得到的的随机数序列不同。

返回值none

使用格式】一般情况下基本使用格式如下:

c
/* 需要包含的头文件 */
#include <stdlib.h>
#include <time.h>

/* 至少应该有的语句 */
srand(time(NULL));

注意事项】该函数需要与与rand()一起使用。

3.2 使用实例

c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int arc, char *argv[])
{
	int i = 0;

	/* 打印随机数序列 */
	srand(time(NULL));
	printf("[");
	for (i = 0; i < 8; i++)
	{
		printf("%d", rand() % 100);
		if (i != 8 - 1)
			printf(", ");
	}
	printf("]\n");

	return 0;
}

在终端执行以下命令编译程序:

shell
gcc test.c -Wall # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,多运行几次,会发现产生的随机数序列是不同的了:

image-20220621161530781

4. rand_r() 函数

4.1 函数说明

linux下可以使用man 3 rand_r命令查看该函数的帮助手册。

c
/* 需包含的头文件 */
#include <stdlib.h>

/* 函数声明 */
int rand_r(unsigned int *seedp);

函数说明】该函数也用于生成随机数,与rand()不同的是,它自带种子参数。

函数参数

  • seedpunsigned int类型的指针变量,用于在调用之间存储状态,说实话,有点不理解这句话。在man手册中有说,如果rand_r()被调用时带有seedp指向的整数的相同初始值,并且在调用之间不修改该值,那么将产生相同的伪随机序列。当这个值改变的时候,产生的随机序列也会发生变化。

返回值int类型,返回一个介于0RAND_MAX(包含)之间的值,也就是闭区间上的[0, RAND_MAX]

使用格式】一般情况下基本使用格式如下:

c
/* 需要包含的头文件 */
#include <time.h>

/* 至少应该有的语句 */
int a;
unsigned int b = 1;
a = rand_r(&b);

注意事项

(1)该函数与rand()一样,每一次运行程序所得到的随机数序列都是相同的,想要每次产生不同的随机序列,我们可以使用日历时间作为随机数产生的种子,因为时间是不断变化的,所以每次启动程序,都会有不一样的种子,这也就意味着得到的随机序列也是不同的。

(2)seedp的值,在一次调用之后似乎会自己变化,需要重新赋值,至少我自己尝试的时候是有这样的情况产生,无法将这个值++或者--

4.2 使用实例1

下边的这个实例,每次程序启动产生的随机序列都会与上一次一样。

c
#include <stdio.h>
#include <stdlib.h>

int main(int arc, char *argv[])
{
	int i = 0;
	int j = 0;
	unsigned int num = 0;

	/* 打印随机数序列 */
	for(j = 0; j < 5; j++)
	{
		num = j;
		if(j > 3) num = 0;
		printf("j = %d,num = %d[", j, num);
		for (i = 0; i < 8; i++)
		{
			printf("%d", rand_r(&num) % 100);
			if (i != 8 - 1)
				printf(", ");
		}
		printf("]\n");
	}
	return 0;
}

在终端执行以下命令编译程序:

shell
gcc test.c -Wall # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,多运行几次,会发现产生的随机数序列是相同的:

image-20220621161920515

4.3 使用实例2

下边的这个实例,每次程序启动产生的随机序列都会与上一次不同。

c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int arc, char *argv[])
{
	int i = 0;
	unsigned int tm;
	tm = (unsigned int)time(NULL);
	/* 打印随机数序列 */

	printf("[");
	for (i = 0; i < 8; i++)
	{
		printf("%d", rand_r(&tm) % 100);
		if (i != 8 - 1)
			printf(", ");
	}
	printf("]\n");

	return 0;
}

在终端执行以下命令编译程序:

shell
gcc test.c -Wall # 生成可执行文件 a.out 
./a.out # 执行可执行程序

然后,终端会有以下信息显示:

image-20220621162216261