C++11 随机数生成——告别 rand()

文章目录

  • [C++11 随机数生成------告别 rand()](#C++11 随机数生成——告别 rand())
    • [一、C 语言的 rand() 有什么问题](#一、C 语言的 rand() 有什么问题)
    • [二、C++11 的三大组件](#二、C++11 的三大组件)
    • 三、实战例子
      • [3.1 模拟温度:42°C 上下波动 2°C](#3.1 模拟温度:42°C 上下波动 2°C)
      • [3.2 模拟误码率:极小数值](#3.2 模拟误码率:极小数值)
      • [3.3 生成整数范围](#3.3 生成整数范围)
    • 四、逐行拆解
      • `std::random_device{}()`
      • [`std::mt19937 rng{种子}`](#std::mt19937 rng{种子})
      • [`std::uniform_real_distribution<double>(min, max)(rng)`](#std::uniform_real_distribution<double>(min, max)(rng))
    • [五、为什么用 static 修饰引擎](#五、为什么用 static 修饰引擎)
    • 六、为什么加锁
    • [七、C++11 还支持其他分布](#七、C++11 还支持其他分布)
    • [八、C vs C++11 对比](#八、C vs C++11 对比)
    • 九、面试该怎么说

C++11 随机数生成------告别 rand()

最近在嵌入式项目里看到了一种从来没用过的随机数写法,研究了一下发现这竟然是 C++11 标准的正式写法。比 C 语言的 rand() 好用太多了,记录下来。


一、C 语言的 rand() 有什么问题

cpp 复制代码
#include <cstdlib>
#include <ctime>

srand(time(NULL));    // 用当前时间做种子

// 想生成 40.0 到 44.0 之间的浮点数:
double temp = 40.0 + (rand() % 400) / 10.0;
// 一坨计算,不好读
// 而且 rand() 有几个硬伤
rand() 的问题 说明
随机质量差 周期短(通常是 2^31-1),低位不够随机
指定范围麻烦 要自己用 % 和乘法算,容易出错
线程不安全 内部有全局状态,多线程同时调会乱
分布单一 只有均匀分布,没法生成正态分布等

二、C++11 的三大组件

C++11 把随机数拆成了三个组件,各司其职:

复制代码
① 真随机数设备(random_device) → 生成种子(从硬件噪声获取)
         ↓
② 随机数引擎(mt19937)        → 根据种子生成高质量伪随机序列
         ↓
③ 分布(distribution)         → 把引擎的原始输出映射到你需要的范围

三、实战例子

3.1 模拟温度:42°C 上下波动 2°C

cpp 复制代码
#include <random>
#include <mutex>

double simulateTemperature() {
    static std::mt19937 rng{std::random_device{}()};  // 引擎只创建一次
    static std::mutex mtx;                            // 保护 rng,它不是线程安全的

    std::lock_guard<std::mutex> lock(mtx);
    return 42.0 + std::uniform_real_distribution<double>(-2.0, 2.0)(rng);
    //         ↑                                       ↑    ↑
    //     基准温度                             均匀分布    用 rng 引擎
    //                                          区间 [-2.0, 2.0]
}

3.2 模拟误码率:极小数值

cpp 复制代码
double simulateBER() {
    static std::mt19937 rng{std::random_device{}()};
    static std::mutex mtx;

    std::lock_guard<std::mutex> lock(mtx);
    return 1.2e-7 + std::uniform_real_distribution<double>(-2e-8, 2e-8)(rng);
    //     ↑ 0.00000012 ± 0.00000002
}

3.3 生成整数范围

cpp 复制代码
// 模拟 1 到 100 之间的随机整数
std::uniform_int_distribution<int>(1, 100)(rng);
// 等价于 rand() % 100 + 1,但分布绝对均匀

四、逐行拆解

std::random_device{}()

cpp 复制代码
std::random_device{}     // 创建一个 random_device 临时对象
                     ()   // 调用它的 operator(),拿到一个真随机数作为种子

真随机数不是算出来的------它从 CPU 的硬件噪声(热噪、时钟抖动)获得,不可预测。

std::mt19937 rng{种子}

cpp 复制代码
std::mt19937 rng{std::random_device{}()};
//   ↑
// Mersenne Twister 19937 算法
// 周期 = 2^19937 - 1(天文数字)
// 性能和质量都是顶尖水平

std::uniform_real_distribution<double>(min, max)(rng)

cpp 复制代码
std::uniform_real_distribution<double>(-2.0, 2.0)(rng)
//  ↑ 均匀分布                              ↑范围      ↑用哪个随机引擎
//  每个值出现的概率完全相等

五、为什么用 static 修饰引擎

cpp 复制代码
static std::mt19937 rng{std::random_device{}()};
// 如果用 static:第一次调用时初始化一次 → 之后复用一个引擎
// 如果不用 static:每次调用都重建引擎,重新播种
// 高频调用下性能差异巨大

引擎只创建一次、一直复用。 每次调用 dist(rng) 时,引擎继续向前生成下一个随机数,保证随机性。


六、为什么加锁

cpp 复制代码
static std::mutex mtx;
std::lock_guard<std::mutex> lock(mtx);

std::mt19937 不是线程安全的------多个线程同时用同一个 rng 对象会导致内部状态错乱,产生相同的"随机"值。加锁保证同一时刻只有一个线程在用 rng。


七、C++11 还支持其他分布

cpp 复制代码
// 正态分布:均值 50,标准差 10
std::normal_distribution<double>(50.0, 10.0)(rng);

// 伯努利分布:70% 返回 true
std::bernoulli_distribution(0.7)(rng);

// 整数均匀分布:1~6(骰子)
std::uniform_int_distribution<int>(1, 6)(rng);

这是 rand() 完全做不到的------你需要正态分布数据来模拟传感器噪声?一行搞定。


八、C vs C++11 对比

cpp 复制代码
// C 语言:模拟温度 40~44
srand(time(NULL));
double temp1 = 40.0 + (rand() % 400) / 100.0;

// C++11:模拟温度 40~44
std::mt19937 rng{std::random_device{}()};
double temp2 = 40.0 + std::uniform_real_distribution<double>(0.0, 4.0)(rng);

// C:模拟掷骰子
int dice1 = rand() % 6 + 1;   // 有偏差!低位不够随机

// C++11:模拟掷骰子
int dice2 = std::uniform_int_distribution<int>(1, 6)(rng);  // 完全均匀

九、面试该怎么说

"项目中用 C++11 的 <random> 库代替 C 的 rand()。采用 std::mt19937 引擎 + std::uniform_real_distribution 分布的三层架构------硬件真随机种子、高质量伪随机引擎、均匀分布映射到指定范围。用 static 保证引擎只初始化一次,用 std::mutex 保护非线程安全的引擎。这种写法比 rand() 随机质量更高、API 更清晰、支持多种概率分布。"


嵌入式项目里也常常要用随机数------模拟传感器噪声、测试数据生成、通信超时抖动。C++11 的 <random> 是标准库里的,任何平台都能用。

相关推荐
海清河晏1111 小时前
数据结构 | 二叉平衡搜索树
开发语言·数据结构·visual studio
kuonyuma1 小时前
java之动态代理
java·开发语言
KouFiee1 小时前
同名隐藏基础
开发语言·c++
z落落1 小时前
C# Task WaitAll、WaitAny、WhenAll、WhenAny
开发语言·c#
兰令水1 小时前
hot100【acm版】【2026.7.11/12打卡-java版本】
java·开发语言·数据结构·算法·职场和发展
从零开始的代码生活_2 小时前
C++ string 详解:常用接口、字符串算法与深拷贝实现
开发语言·c++·后端·学习·算法
m0_738120722 小时前
PHP代码审计基础——面向对象(四)
android·开发语言·网络·安全·github·php
2601_963771372 小时前
10 Best PHP Media CMS and Scripts for Web Creators in 2026
开发语言·前端·php
阿里嘎多学长3 小时前
2026-07-09 GitHub 热点项目精选
开发语言·程序员·github·代码托管