29 C 语言中的随机数实现:rand 与 srand

news2024/11/23 2:26:59

目录

1 为什么需要随机数?

1.1 背景介绍

1.2 应用场景        

2 C 语言实现随机数

2.1 rand() 函数

2.1.1 函数原型

2.1.2 功能说明

2.1.3 案例演示

2.2 srand() 函数

2.2.1 函数原型

2.2.2 功能说明

2.2.3 案例演示

2.3 指定范围的随机数

2.3.1  获取 [min, max] 范围内的随机整数

2.3.2  获取 [min, max) 范围内的随机浮点数

2.3.3 函数封装

2.3.4 案例演示

3 注意事项

4 综合案例

4.1 随机密码生成器

4.2 随机数生成器


1 为什么需要随机数?

        在数字世界的各个领域,随机数扮演着至关重要的角色。它们不仅是确保系统公平性与不可预测性的基石,也是保障数据安全、优化算法性能、模拟现实世界复杂现象的关键工具。随机数生成(Random Number Generation, RNG)的需求源于多个方面,包括但不限于编程实践、娱乐游戏、科学研究以及信息安全等领域。

1.1 背景介绍

  • 编程:在软件开发中,随机数常用于实现诸如抽奖、随机排序、负载均衡等功能,它们帮助程序做出不可预测的选择,提高用户体验和系统效率。
  • 游戏开发:游戏世界充满了未知与惊喜,随机事件如掉落物品、怪物刷新、玩家属性加成等,都是基于随机数来实现的,这些机制大大增强了游戏的趣味性和挑战性。
  • 模拟实验:在科学研究中,模拟实验是探索自然规律、预测未来趋势的重要手段。随机数被用于构建模型的随机性部分,如粒子运动、人口增长模拟等,以确保模拟结果更加接近真实世界的复杂性和不确定性。
  • 密码学:在信息安全领域,随机数更是不可或缺。加密算法的密钥生成、随机数填充(如填充块密码的最后一个分组)、会话密钥的协商等,都依赖于高质量的随机数来保证通信的安全性和数据的保密性。

1.2 应用场景        

  • 游戏中的随机事件:在《魔兽世界》等角色扮演游戏中,随机掉落的装备和道具、随机触发的剧情事件等,都是由随机数控制的,这种机制保持了游戏的新鲜感和玩家的探索欲望。
  • 数据分析中的样本选择:在统计学和数据分析中,研究者经常需要从大数据集中随机抽取样本进行分析,以确保样本的代表性和结果的可靠性。例如,市场调查中的随机抽样就依赖于随机数生成。
  • 加密算法的密钥生成:在 SSL/TLS 协议中,每次建立安全连接时都会生成一对唯一的会话密钥,这些密钥的生成过程涉及到复杂的随机数算法,以确保通信双方之间传输的数据不被未经授权的第三方窃取或篡改。
  • 随机化算法:在计算机科学中,许多算法通过引入随机性来提高性能或解决特定问题。例如,遗传算法、模拟退火算法等启发式搜索算法,通过随机变异和选择机制来探索解空间,寻找问题的近似最优解。

2 C 语言实现随机数

        在 C 语言中,实现随机数通常依赖于标准库中的 <stdlib.h> 头文件,特别是 rand() 函数和 srand() 函数。

2.1 rand() 函数

2.1.1 函数原型

        rand() 函数是 C 语言标准库 <stdlib.h> 中用于生成伪随机数的函数。它没有参数,返回一个 int 类型的值,表示生成的伪随机数。

#include <stdlib.h>
int rand(void);

2.1.2 功能说明

        rand() 函数生成一个伪随机数。伪随机数是通过一个算法(通常基于当前时间或其他输入值)产生的,因此它们不是真正的随机数,而是看起来随机的。由于算法的确定性,给定相同的种子(通过 srand() 函数设置),rand() 函数将产生相同的随机数序列

2.1.3 案例演示

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

int main() {
    // 生成一个随机数
    int random_number = rand();

    printf("生成的随机数是: %d\n", random_number);

    return 0;
}

2.2 srand() 函数

2.2.1 函数原型

        srand() 函数用于设置随机数生成的种子,它是 C 语言标准库 <stdlib.h> 中的一个函数。srand() 函数的原型如下:

#include <stdlib.h>  
void srand(unsigned int seed);
  • unsigned int seed 是函数的参数,表示要设置的种子值。函数没有返回值(即返回类型为 void)。

2.2.2 功能说明

        srand() 函数用于初始化随机数生成器(RNG)在调用 rand() 函数生成随机数之前,应该先调用 srand() 函数来设置种子值。种子值是一个整数,它决定了随机数生成算法的起始点。如果不调用 srand(),或者每次程序运行时都使用相同的种子值,那么 rand() 函数将产生相同的随机数序列。

        通常,使用当前时间(通过 <time.h> 头文件中的 time() 函数获取)作为种子值,因为这样可以确保每次程序运行时都能得到不同的随机数序列。

2.2.3 案例演示

        以下是一个使用 srand() 和 rand() 函数的示例程序,该程序生成并打印了 10 个随机数:

#include <stdio.h>  
#include <stdlib.h>  
#include <time.h>  
  
int main() {  
    // 设置随机数种子为当前时间  
    srand((unsigned int)time(NULL));  
  
    // 生成并打印 10 个随机数  
    for (int i = 0; i < 10; i++) {  
        // 生成随机数并打印  
        printf("第%d个随机数: %d\n", i + 1, rand());  
    }  
  
    return 0;  
}

2.3 指定范围的随机数

2.3.1  获取 [min, max] 范围内的随机整数

        rand() 函数会生成一个范围在 [0, RAND_MAX] 范围内的整数,其中 RAND_MAX 是 <stdlib.h> 中定义的一个常量,表示 rand() 函数能返回的最大值。为了将生成的随机数限制在指定的范围内,可以使用取模运算(%)和适当的偏移量。

        假设要生成一个在 [min, max] 范围内的随机整数,可以使用以下公式:

// 生成一个在 [min, max] 范围内的随机整数
int randomNumberInRange = (rand() % (max - min + 1)) + min;

解释如下 :

        1. 理解 rand() 函数:
        rand() 是一个标准库函数,用于生成一个伪随机数。它返回一个在 [0, RAND_MAX] 范围上的整数,其中 RAND_MAX 是 <stdlib.h> 中定义的一个常量,表示 rand() 函数能返回的最大值。

        2. 计算模数 (max - min + 1):

        我们需要确定随机数的范围大小,即从 min 到 max 上有多少个整数。这可以通过计算 max - min + 1 来实现。例如,如果 min 是 10,max 是 20,那么范围大小就是 20 - 10 + 1 = 11,意味着有 11 个整数(10, 11, 12, ..., 20)。

        3. 使用模运算符 %:

        接下来,我们使用模运算符 % 来限制 rand() 函数生成的随机数。rand() % (max - min + 1) 的作用是将 rand() 生成的随机数限制在一个更小的范围内,即从 0 到 max - min(实际上是到 max - min 的下一个整数,因为模运算的结果是从 0 开始的)。由于我们想要的范围是从 min 开始的,所以我们需要的是从 0 到 max - min 的整数,这样加上 min 后就能得到从 min 到 max 的整数了。

        4. 加上 min:

        最后,我们将上一步得到的结果(一个在 [0, max-min] 范围内的整数)加上 min。这样,原本在 [0, max-min] 范围内的整数就被 “平移” 到了 [min, max] 范围内。

2.3.2  获取 [min, max) 范围内的随机浮点数

        假设要生成一个在 [min, max) 范围内的随机浮点数,可以使用以下公式:

// 生成一个在 [min, max) 范围内的随机浮点数
(double)rand() / RAND_MAX * (max - min) + min;

解释如下 : 

        1. 类型转换:

        (double)rand():将 rand() 函数生成的整数转换为 double 类型。这是为了确保后续运算能够产生浮点数结果。

        2. 生成 [0.0, 1.0) 范围内的浮点数:

        (double)rand() / RAND_MAX:由于 rand() 返回一个 [0, RAND_MAX] 范围内的整数,而 RAND_MAX 是 rand() 能返回的最大值,因此 (double)rand() / RAND_MAX 将生成一个 [0.0, 1.0) 范围内的浮点数。注意这里是不包括 1.0 的,因为 rand() 几乎不可能恰好返回 RAND_MAX(尽管在理论上有可能,但实际上由于浮点数的表示方式,这种情况几乎不会发生)。

        3. 调整范围到 [0.0, max-min):

        接下来,我们将上一步得到的浮点数乘以 (max - min)。这样,原本在 [0.0, 1.0) 范围内的浮点数就被 “拉伸” 到了 [0.0, max-min) 范围内。这个新范围仍然不包括其上限(即 max-min),但包括了下限 0.0。

        4. 平移范围到 [min, max):

        最后,我们通过加上 min 将这个范围 “平移” 到 [min, max)。现在,我们得到了一个在 [min, max) 范围内的随机浮点数,它包括了 min 但不包括 max。

        5. 关于端点值:

  • min 是可以被取到的,因为我们在最后一步加上了 min
  • max 是取不到的,这是由浮点数的表示和运算方式决定的。特别是,当我们乘以 (max - min) 并可能进行四舍五入时,结果永远不会恰好等于 max(除非 max 和 min 相等,但这种情况下范围就没有意义了)。此外,即使在没有四舍五入的情况下,由于浮点数的精度限制,也很难精确表示 max 这样的特定值。

2.3.3 函数封装

        可以将生成指定范围随机数的功能编写成函数,在需要的时候,调用即可,如下所示:

// 生成指定范围 [min,max] 的随机整数
int generateRandomInt(int min, int max)
{
    return (rand() % (max - min + 1)) + min;
}

// 生成指定范围内 [min,max) 的随机浮点数
double generateRandomFloat(double min, double max)
{
    return (double)rand() / RAND_MAX * (max - min) + min;
}

2.3.4 案例演示

        以下是一个完整的示例,展示了如何生成一个在 [10, 50] 范围内的随机数:

#include <stdio.h>  
#include <stdlib.h>  
#include <time.h>  
  
int main() {  
    // 设置随机数种子  
    srand((unsigned)time(NULL));  
  
    // 生成并打印一个在 [10, 50] 范围内的随机数  
    int min = 10;  
    int max = 50;  
    int randomNumberInRange = (rand() % (max - min + 1)) + min;  
    printf("随机数: %d\n", randomNumberInRange);  
  
    return 0;  
}

3 注意事项

        种子设置时机应该在程序开始时(通常是在 main() 函数的开头)调用 srand() 函数,并且只调用一次。如果在循环中多次调用 srand() 并使用相同的种子(如连续调用 time(NULL) 但时间没有变化),则可能会得到相同的随机数序列。

        种子值的选择为了得到不同的随机数序列,应该选择一个随时间变化的值作为种子,如当前时间。但是,如果程序在极短的时间内被多次执行(如在一秒内多次启动和停止),则可能仍然会得到相同的随机数序列。在这种情况下,可以考虑使用更复杂的种子生成策略,如结合多个不同的时间戳或系统状态值。

        随机数质量:rand() 函数生成的随机数质量(如周期长度、分布均匀性等)可能不足以满足所有应用的需求。在需要高质量随机数的场合(如加密应用),应该考虑使用专门的随机数生成库或函数。

        可移植性:尽管 srand() 和 rand() 是 C 语言标准库的一部分,但不同编译器或平台上的实现可能有所不同。因此,在跨平台开发中,应该注意测试随机数生成的行为是否符合预期。


4 综合案例

4.1 随机密码生成器

        编写一个 C 语言程序,该程序能够生成一个指定长度的随机密码。密码应包含大写字母、小写字母、数字以及特殊字符(如 !@#$%^&*() 等)。用户需要输入密码的长度,然后程序输出一个符合要求的随机密码。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

// 定义字符集(全局字符串)
const char *chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;':\",./<>?";

// 生成随机密码的函数
void generateRandomPassword(int length)
{
    if (length <= 0)
    {
        printf("密码长度必须为正数。\n");
        return;
    }

    for (int i = 0; i < length; i++)
    {
        printf("%c", getRandomChar());
    }
    printf("\n");
}

// 生成随机字符的函数
char getRandomChar()
{
    // 生成索引-随机数范围 [0, chars长度(不包括结束符) - 1]
    int index = rand() % (int)strlen(chars);
    return chars[index];
}

// 主函数
int main()
{
    int length;

    // 设置随机数种子
    srand((unsigned)time(NULL));

    // 获取用户输入的密码长度
    printf("请输入密码的长度:");
    scanf("%d", &length);

    // 生成并打印随机密码
    generateRandomPassword(length);

    return 0;
}

4.2 随机数生成器

        编写一个 C 语言程序,实现以下功能:

  • 生成一个指定范围内的随机整数。
  • 生成一个指定范围内的随机浮点数。
  • 生成一个随机字符(大写字母)。
  • 生成一个包含 10 个随机整数的数组,并计算数组的平均值。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// 生成指定范围 [min,max] 的随机整数
int generateRandomInt(int min, int max)
{
    return (rand() % (max - min + 1)) + min;
}

// 生成指定范围内 [min,max) 的随机浮点数
double generateRandomFloat(double min, double max)
{
    return (double)rand() / RAND_MAX * (max - min) + min;
}

// 生成一个随机的大写字母
char generateRandomChar()
{
    return (char)(rand() % 26 + 'A');
}

// 生成一个包含 10 个随机整数的数组,并计算平均值
double generateRandomArrayAndAverage(int min, int max)
{
    int array[10];
    int sum = 0;

    for (int i = 0; i < 10; i++)
    {
        array[i] = generateRandomInt(min, max);
        sum += array[i];
        printf("随机整数 %d: %d\n", i + 1, array[i]);
    }

    double average = (double)sum / 10;
    return average;
}

int main()
{
    // 使用当前时间作为随机数生成器的种子
    srand((unsigned int)time(NULL));

    // 生成一个 1 到 100 之间的随机整数
    int randomInt = generateRandomInt(1, 100);
    printf("生成的 1 到 100 之间的随机整数是: %d\n", randomInt);

    // 生成一个 0.0 到 10.0 之间的随机浮点数
    double randomFloat = generateRandomFloat(0.0, 10.0);
    printf("生成的 0.0 到 10.0 之间的随机浮点数是: %f\n", randomFloat);

    // 生成一个随机的大写字母
    char randomChar = generateRandomChar();
    printf("生成的随机大写字母是: %c\n", randomChar);

    // 生成一个包含 10 个随机整数的数组,并计算平均值
    double average = generateRandomArrayAndAverage(1, 100);
    printf("[1-100]中 10 个随机整数的平均值是: %f\n", average);

    return 0;
}

        输出结果如下所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164654.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为什么 qt 成为 c++ 界面编程的第一选择?

一、前言 为什么现在QT越来越成为界面编程的第一选择&#xff0c;笔者从事qt界面编程已经有接近8年&#xff0c;在这之前我做C界面都是基于MFC&#xff0c;也做过5年左右。当时为什么会从MFC转到QT&#xff0c;主要原因是MFC开发界面想做得好看一些十分困难&#xff0c;引用第…

hexo github部署,通过域名访问你的博客

hexo github部署&#xff0c;通过域名访问你的博客 hexo 常用命令hexo github 部署 在部署之前&#xff0c;了解一下hexo的常用命令 hexo 常用命令 hexo new "My New Post" # 新建文章 hexo n "My New Post"hexo generate # 生成静态文件 hexo ghexo serv…

【CTF】Nginx日志注入

Nginx日志注入&#xff1a; 日志包含漏洞的成因还是服务器没有进行严格的过滤 &#xff0c;导致用户可以进行任意文件读取&#xff0c;但是前提是服务器需要开启了记录日志的功能才可以利用这个漏洞。 对于Apache&#xff0c;日志存放路径&#xff1a;/var/log/apache/access.l…

【论文阅读】FedBABU:TOWARD ENHANCED REPRESENTATION FOR FEDERATED IMAGE CLASSIFICATION

算法流程&#xff1a; 训练过程中冻结客户端的头部参数&#xff0c;只训练主体参数。训练完之后再在客户端本地跑几个epoch微调一下&#xff08;文章推荐5个&#xff09;。 由于该算法与FedPer思路过于相似&#xff0c;故读完后跑了个实验。 FedPer:训练过程中只聚合主体参数。…

Redis --- redis事务和分布式事务锁

redis事务基本实现 Redis 可以通过 MULTI&#xff0c;EXEC&#xff0c;DISCARD 和 WATCH 等命令来实现事务(transaction)功能。 > MULTI OK > SET USER "Guide哥" QUEUED > GET USER QUEUED > EXEC 1) OK 2) "Guide哥"使用 MULTI命令后可以输入…

Linux应用开发实验班——JSON-RPC

目录 前言 1.是什么JSON-RPC 2.常用的JSON函数 1.创建JSON 2.根据名字获取JSON 3.获取JSON的值 4.删除JSON 3.如何进行远程调用 服务器 客户端 4.基于JSON-RPC进行硬件操作 课程链接 前言 学习的课程是百问网韦东山老师的课程&#xff0c;对更详细步骤感兴趣的同学…

LINUX网络编程:Tcp(2)

目录 1.Tcp流量控制 2.滑动窗口 2.1滑动窗口的更新 2.2滑动窗口的丢包问题 1.报文丢失的情况 2.ACK丢失的情况 3.拥塞控制 3.1慢启动 3.2拥塞窗口的增长 1.Tcp流量控制 为什会有流量控制&#xff1f; 1.在网络通信中&#xff0c;假如发送方的发送能力特别的强&#xff0…

支付宝沙箱环境 支付

一 什么是沙箱&#xff1a; 沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境 支付宝正式和沙箱环境的区别 &#xff1a; AI&#xff1a; 从沙箱到正式环境&#xff1a; 当应用程序开发完成后&#xff0c;需要将应用程序从沙箱环境迁移到正式环境。 这通常涉及…

opencv图像增强十四:opencv两种白平衡介绍及实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、白平衡介绍二、灰度世界法三、完美反射法 前言 在摄影与影像领域&#xff0c;白平衡是一个至关重要的概念。它直接影响着画面的色彩表现&#xff0c;关系到…

构建网络遇到的问题-AlexNet

1.对模型进行初始化采用的一般代码 def _initialize_weights(self):for m in self.modules(): # 遍历模型每一层if isinstance(m, nn.Conv2d): # 判定m层是否属于nn.Conv2d类型nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu)if m.bias is not None:nn.in…

从自动化到智能化:AI如何推动业务流程自动化

引言&#xff1a;从自动化到智能化的必然趋势 在当今数字化时代&#xff0c;企业为了提升效率、降低成本&#xff0c;纷纷采用自动化技术来简化重复性任务。然而&#xff0c;传统自动化仅限于标准化操作&#xff0c;无法应对复杂的决策和多变的市场环境。随着人工智能&#xff…

基于springboot垃圾分类网站

基于springboot垃圾分类网站 摘 要 本论文主要论述了如何使用JAVA语言开发一个垃圾分类网站 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述垃圾分类网站的当…

Android开发拍身份证带人像框和国徽框效果

Android开发拍身份证带人像框和国徽框效果 拍身份证时往往要带上外框辅助用户拍照&#xff0c;这也是很常见的需求。 一、思路 自定义Camera和自定义拍照的界面&#xff0c;把外框画上去&#xff0c;做个遮罩 二、效果图&#xff1a; Android开发教程实战案例源码分享-拍身…

深入理解计算机系统-Bomb Lab

使用 头歌 平台 GDB 调试器 反汇编函数

动力锂电池电芯壳体市场前景:预计2030年全球市场规模将达到49.2亿美元

动力锂电池罐起着传输能量、承载电解液、保护安全等重要作用&#xff0c;是锂电池的重要组成部分。 据QYResearch调研团队最新报告“全球动力锂电池电芯壳体市场报告2024-2030”显示&#xff0c;预计2030年全球动力锂电池电芯壳体市场规模将达到49.2亿美元&#xff0c;未来几年…

分布式算法

分布式场景下的核心问题 分布式场景下困扰我们的3个核心问题&#xff08;CAP&#xff09;&#xff1a;一致性、可用性、分区容错性。 1、一致性&#xff08;Consistency&#xff09;&#xff1a;无论服务如何拆分&#xff0c;所有实例节点同一时间看到是相同的数据。 2、可用性…

开源链动 2+1 模式 S2B2C 商城小程序:社交电商团队为王的新引擎

摘要&#xff1a;本文深入探讨在社交电商领域中&#xff0c;团队的重要性以及如何借助开源链动 21 模式 S2B2C 商城小程序&#xff0c;打造具有强大竞争力的团队&#xff0c;实现个人价值与影响力的放大&#xff0c;创造被动收入&#xff0c;迈向财富自由之路&#xff0c;同时为…

从汽车高速线束角度浅谈中控屏黑屏、闪屏及信号阈值低故障-之AEM线束测试仪应用案例

故障成因和解决方案 随着车载信息娱乐技术的迅速发展&#xff0c;中控屏已经成为现代汽车的标配。然而&#xff0c;许多主机厂和消费者在车辆使用过程中常常遇到中控屏出现黑屏、闪屏以及信号阈值低等问题&#xff0c;给使用带来了诸多困扰。本文将从汽车高速线束的角度&#…

GPU服务器本地搭建Dify+xinference实现大模型应用

文章目录 前言一、显卡驱动配置1.检测显卡2.安装驱动 二、安装nvidia-docker二、安装Xinference1.拉取镜像2.运行Xinference3.模型部署 三、安装Dify1.下载源代码2.启动 Dify3.访问 Dify 四、Dify构建应用1.配置模型供应商2.聊天助手3.Agent 前言 本文使用的GPU服务器为UCloud…

MySQL: 数据类型介绍

文章目录 数据类型数值类型字符串类型日期类型 数据类型 数值类型 分为整型和浮点型: BIT类似于数据结构中的位图,BIT可以认为是一组二进制bit位. BIT(10)表示这个类型里就存最多10个bit位. 虽然TINYINT和SMALLINT更节省空间,但是还是更推荐使用INT或者BIGINT. 如果存储空间…