c++STL剖析(1)之rand()和srand()

本文介绍了C++中的rand()和srand()两个标准库函数,它们分别用于生成随机整数和设置随机数种子。rand()通过取模操作可以限定生成的随机数范围,而srand()初始化随机数序列,不指定种子时默认为srand(1)。为了获得不同的随机序列,可以使用当前时间作为种子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 其实这两个函数是c的标准库函数,位于<stdlib.h>,兼容于c++

rand()

官方链接:http://www.cplusplus.com/reference/cstdlib/rand/

格式:

int rand (void);

使用方式:

v1 = rand() % 100;         // v1 in the range 0 to 99
v2 = rand() % 100 + 1;     // v2 in the range 1 to 100
v3 = rand() % 30 + 1985;   // v3 in the range 1985-2014

个人理解:

rand()函数本身是在0到RAND_MAX(一个写在头文件中的宏定义,很大的一个数字)之间随机产生一个整数,rand()%100,取余的操作把随机数控制在0到100之内,rand()%100+1,再加上一个常数,就可以控制在你想要的范围。

srand()

官方链接:http://www.cplusplus.com/reference/cstdlib/srand/

格式:

void srand (unsigned int seed);

 使用方法:

/* srand example */
#include <stdio.h
<think>好的,用户现在想了解C++ stdlib.h中的rand函数的实现源码,以及在哪里可以找到这些源码。首先,我需要回忆一下C标准库中rand函数的常见实现方式。通常,rand使用的是线性同余生成器(LCG),但不同的编译器可能有不同的实现,比如glibc、MSVC或者LLVM的libc++。 接下来,用户可能想知道具体的源码在哪里查找。我需要分别说明不同编译器的源码位置,比如glibc可以在其Git仓库中找到,而MSVC可能需要通过Visual Studio安装目录或者官方文档。同时,用户可能对实现的细节感兴趣,比如算法原理、种子处理线程安全问题。 需要确认用户是否有特定的编译器环境,比如是否在使用GCC、Clang还是MSVC,因为不同实现的代码路径不同。另外,用户可能想知道如何查看自己系统中使用的rand函数的具体实现,可能需要指导他们查看本地安装的源码或者在线资源。 还需要注意,直接查看标准库源码对于新手来说可能有些困难,所以可能需要给出具体的代码示例或算法步骤,帮助理解。此外,提醒用户rand函数的局限性C++11推荐的替代方案,比如<random>库,可能也是有帮助的。 最后,确保回答结构清晰,分点说明不同编译器的实现源码位置,并解释算法原理,同时给出示例代码注意事项。需要避免过于技术化的术语,但保持准确性,确保用户能够理解并找到所需的信息。</think>在 C/C++ 中 `rand()` 函数的实现因编译器而异,以下是常见实现的深度解析: --- ### **一、核心实现原理** 主流实现普遍采用 **线性同余生成器(LCG)** 算法: $$ X_{n+1} = (a \times X_n + c) \mod m $$ 其中: - $a$ = 乘数(multiplier) - $c$ = 增量(increment) - $m$ = 模数(决定取值范围) - $X_0$ = 种子(由 `srand()` 设置) --- ### **二、不同编译器的具体实现** #### **1. GNU glibc 实现(Linux/GCC)** 路径:`glibc/stdlib/random_r.c` ```c // 典型参数:a=1103515245, c=12345, m=2^31 int __random_r (struct random_data *buf, int32_t *result) { int32_t *state = buf->state; int32_t val = state[0]; val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; state[0] = val; *result = val; return 0; } ``` 特点:使用 31 位精度(高位被截断) #### **2. Microsoft VC++ 实现** 路径:`%VS安装路径%/VC/crt/src/rand.c` ```c // 经典参数:a=214013, c=2531011, m=2^32 void __cdecl srand(unsigned int seed) { _getptd()->_holdrand = (unsigned long)seed; } int __cdecl rand(void) { _ptiddata ptd = _getptd(); return( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) & 0x7fff ); } ``` 特点:返回值的有效位数仅 15 位 #### **3. LLVM libc++ 实现(macOS/Clang)** 路径:`libc/src/stdlib/rand.cpp` ```c static unsigned long next = 1; int rand(void) { next = next * 1103515245 + 12345; return (unsigned int)(next / 65536) % 32768; } void srand(unsigned int seed) { next = seed; } ``` 特点:保留传统 BSD 实现方式 --- ### **三、源码获取途径** 1. **GNU glibc**: - 在线浏览:https://sourceware.org/git/?p=glibc.git - 本地安装:`apt-get source glibc-source`(Debian/Ubuntu) 2. **MSVC CRT**: - Visual Studio 安装目录:`VC\crt\src` - 开源版本:https://github.com/microsoft/STL 3. **LLVM libc++**: - 官方仓库:https://github.com/llvm/llvm-project/tree/main/libcxx 4. **在线工具**: - Compiler Explorer:https://godbolt.org/(可查看汇编实现) --- ### **四、关键实现细节** 1. **线程安全性**: - glibc 使用 `__thread` 实现线程局部存储 - MSVC 通过 `_getptd()` 获取线程私有数据 2. **种子处理**: ```c // 典型种子初始化(未设置时默认种子为1) unsigned long _holdrand = 1; // 时间种子示例 srand((unsigned)time(NULL)); ``` 3. **范围限制**: - 通过位掩码实现范围控制 - 例如:`& 0x7FFF` 得到 0-32767 的数值 --- ### **五、算法局限性** 1. **周期性重复**:所有 LCG 实现都有周期限制(如 glibc 的周期为 $2^{31}$) 2. **低位随机性差**:建议使用高位比特(如 `rand() >> 16`) 3. **非加密安全**:可通过观察输出序列推测种子 --- ### **六、现代替代方案(C++11+)** ```cpp #include <random> std::mt19937_64 engine(std::random_device{}()); std::uniform_int_distribution<int> dist(0,99); int val = dist(engine); // 高质量随机数 ``` --- ### **七、快速测试示例** ```cpp #include <iostream> #include <cstdlib> int main() { srand(1); // 固定种子可复现序列 for(int i=0; i<5; ++i) { std::cout << rand() << " "; } // 典型输出(glibc): 1804289383 846930886 1681692777... } ``` --- ### **附:历史演进** - 1988 ANSI C:首次标准化 - 1999 C99:明确要求至少 32767 的 RAND_MAX - 2011 C++11:推荐使用 `<random>` 替代 建议需要高质量随机数时优先使用 C++11 的 `<random>` 库。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值