LV05-07-Linux系统-03-随机数

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

点击查看使用工具及版本
Windows windows11
Ubuntu Ubuntu16.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
SecureCRT Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日
开发板 正点原子 i.MX6ULL Linux阿尔法开发板
uboot NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)
linux内核 linux-4.15(NXP官方提供)
STM32开发板 正点原子战舰V3(STM32F103ZET6)
点击查看本文参考资料
参考方向 参考原文
------
点击查看相关文件下载
--- ---

四、随机数

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

1. 伪随机数?

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

2. rand() 函数

2.1 函数说明

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

1
2
3
4
5
/* 需包含的头文件 */
#include <stdlib.h>

/* 函数声明 */
int rand(void);

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

【函数参数】none

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

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

1
2
3
4
5
6
/* 需要包含的头文件 */
#include <stdlib.h>

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

【注意事项】

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

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

2.2 使用实例

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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;
}

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

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

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

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

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

3. srand() 函数

3.1 函数说明

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

1
2
3
4
5
/* 需包含的头文件 */
#include <stdlib.h>

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

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

【函数参数】

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

【返回值】none

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

1
2
3
4
5
6
/* 需要包含的头文件 */
#include <stdlib.h>
#include <time.h>

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

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

3.2 使用实例

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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;
}

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

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

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

image-20220621161530781

4. rand_r() 函数

4.1 函数说明

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

1
2
3
4
5
/* 需包含的头文件 */
#include <stdlib.h>

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

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

【函数参数】

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

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

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

1
2
3
4
5
6
7
/* 需要包含的头文件 */
#include <time.h>

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

【注意事项】

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

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

4.2 使用实例1

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

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#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;
}

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

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

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

image-20220621161920515

4.3 使用实例2

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

点击查看实例
test.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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;
}

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

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

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

image-20220621162216261