c++中获取随机数
在学习数据结构和算法时,我们经常需要获得测试样例,这是大概率就会用到随机数构造测试样例。接下来将介绍c和c++中获取随机数的方法。
c语言中的随机数
在c语言中生成随机数需要使用rand
函数,该函数根据种子 和特定公式生成一个伪随机数。我们可以使用srand
更改种子,从而生成其它随机数。
c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
printf("%d\n", rand());
printf("%d\n", rand());
srand((unsigned int)time(NULL));
printf("%d\n", rand());
return 0;
}
生成一定范围内的随机数
c
int r1 = rand() % 100;//生成0到99的随机数
int r2 = rand() % 100 + 11;//生成11到99的随机数
c++中的随机数
C++ 中的随机数生成主要分为两大流派:C++11 之前传统的 rand()
和 srand()
,以及 C++11 引入的现代 <random>
库。后者在灵活性、可控性和随机数质量上都有显著提升。
特性维度 | 传统方法 (rand() / srand() ) |
现代方法 (<random> 库) |
---|---|---|
所属头文件 | <cstdlib> |
<random> |
随机数质量 | 较低,周期性短,易预测 | 高,提供多种高质量引擎(如梅森旋转) |
分布控制 | 需手动取模,容易引入偏差,仅支持均匀分布 | 内置多种概率分布(均匀、正态、泊松等),精确控制 |
种子设置 | srand(seed) ,常用time(NULL) |
方式多样,如std::random_device |
线程安全 | 通常不是线程安全的 | 可通过为每个线程创建独立的引擎实例实现 |
适用场景 | 简单、对随机性要求不高的场景 | 仿真、游戏、测试、密码学等对随机性要求高的场景 |
🔧 现代 <random>
库的核心组件
<random>
库通过随机数引擎 、随机数分布 和种子这三个核心概念的分离,提供了强大的灵活性。
-
随机数引擎 (Random Number Engine)
引擎是生成原始随机数序列的核心。常见的几种引擎包括:
std::default_random_engine
:编译器默认选择的引擎,方便但具体实现和性能可能不同。std::mt19937
:基于梅森旋转算法 ,是目前最常用的高质量伪随机数引擎之一,周期极长(2^19937-1),性能良好。std::mt19937_64
:64位版本的梅森旋转引擎,能生成更大范围的随机数。std::linear_congruential_engine
:一种更古老、更简单的引擎,速度很快,但随机性质量通常不如梅森旋转。
-
随机数分布 (Random Number Distribution)
分布器将引擎产生的原始随机数映射到你想要的特定范围或概率分布上。这是
<random>
库强大之处。- 均匀分布 (Uniform Distribution) :
std::uniform_int_distribution<int>
:生成指定范围内的整数,每个数出现概率相等。std::uniform_real_distribution<double>
:生成指定范围内的浮点数,每个数出现概率相等。
- 正态分布 (Normal Distribution / Gaussian Distribution) :
std::normal_distribution<double>
:生成符合正态分布(高斯分布)的随机数,需要指定均值(mean)和标准差(stddev)。
- 其他常见分布 :
std::bernoulli_distribution
:生成布尔值,模拟伯努利试验(如掷硬币)。std::poisson_distribution<int>
:生成符合泊松分布的随机数。- ...以及其他许多分布(如指数分布、二项分布等)。
- 均匀分布 (Uniform Distribution) :
-
随机数种子 (Random Seed)
种子用于初始化随机数引擎的状态,决定了整个随机序列的起点。
- 使用相同的种子 初始化同一个引擎,一定会产生完全相同的随机数序列 。这在重现程序行为(如调试)时非常有用。
- 为了每次运行程序都能得到不同的随机序列,通常需要使用真随机数或变化的值作为种子。
std::random_device
:这是一个非确定性随机数生成器 ,通常会尝试调用操作系统提供的真随机数源(如硬件噪声)。它是获取随机种子的首选方式。
🚀 如何使用 <random>
库
基本的使用步骤是:选择引擎 -> 初始化种子 -> 选择分布 -> 生成随机数。
生成均匀分布的随机整数
cpp
#include <iostream>
#include <random>
int main() {
// 1. 使用std::random_device获取真随机数种子
std::random_device rd;
// 2. 用获取的种子初始化梅森旋转引擎
std::mt19937 gen(rd());
// 3. 定义一个均匀整数分布,范围[1, 100]
std::uniform_int_distribution<int> dis(1, 100);
// 4. 生成随机数:分布对象(引擎对象)
int random_number = dis(gen);
std::cout << "Random number between 1 and 100: " << random_number << std::endl;
return 0;
}
生成均匀分布的随机浮点数
cpp
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
// 生成范围在 [0.0, 1.0) 的随机浮点数
std::uniform_real_distribution<double> dis(0.0, 1.0);
for (int i = 0; i < 5; ++i) {
std::cout << dis(gen) << std::endl;
}
return 0;
}
生成正态分布的随机数
cpp
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
// 均值为 5.0,标准差为 2.0 的正态分布
std::normal_distribution<double> dis(5.0, 2.0);
for (int i = 0; i < 10; ++i) {
std::cout << dis(gen) << std::endl;
}
return 0;
}
需要可重复的随机序列时(例如用于调试)
cpp
#include <iostream>
#include <random>
int main() {
// 使用一个固定的种子(比如42)
std::mt19937 gen(42); // 固定种子
std::uniform_int_distribution<int> dis(1, 6);
// 每次运行程序,都会生成相同的"随机"序列
for (int i = 0; i < 5; ++i) {
std::cout << "Dice roll: " << dis(gen) << std::endl;
}
return 0;
}