1. C++中获取随机数的几种方法
1.1 随机数基本概念:
-
随机数:在一定范围内[a, z],每个数出现的概率相等并且无法预测下一个数的数值序列。
-
伪随机数生成器(PRNG)
- 原理:由一个状态寄存器和一个更新函数组成,初始状态由种子决定,更新状态会根据当前状态生成下一个状态,并输出一个伪随机数
- 种子:伪随机数生成器的初始值,决定了随机数开始时的状态,由于随机数基于算法与随机数生成器初始时的状态产生随机序列,因此相同的种子产生完全相同的随机序列
2. C++中获取随机数:
2.1 基本流程:
1. 设置随机数种子
1. 获取随机数(整数、浮点数)
2.2 随机数种子来源:
time()
函数- 获取当前时间戳,在多线程场景下,由于time函数的精度有限,可能产生相同的种子,生成相似的随机序列
std::random_device
- 是一个非确定性的随机数源,从操作系统或硬件设备重获取真正的随机信息
2. 3获取随机数:
- C cstdlib库中rand函数
#include <ctime>
#include <cstdlib>
#include <iostream>int main() {// 设置随机数种子std::srand(time(nullptr));std::cout << "RAND_MAX" << RAND_MAX << std::endl;for (int i=0; i<10;++i) {// 获取随机数std::cout << "random value: " << rand() << std::endl;// 通过 % 取余获取指定范围的随机数std::cout << "random range 1 100: " << rand() % 100 << std::endl;}
};
- C++ random库 (c++11)
#include <random>
#include <iostream>int main() {// 指定种子std::default_random_engine engine(std::random_device{}());int count = 10;// 指定范围:整数std::uniform_int_distribution<int> rand_int_generator(0, 100);for (int i=0; i<10; ++i) {std::cout << "int random value:" << rand_int_generator(engine) << std::endl;}// 指定范围:浮点数std::uniform_real_distribution<double> rand_double_generator(0, 1);for (int i=0; i<10; ++i) {std::cout << "double random value:" << rand_double_generator(engine) << std::endl;}
};
- 随机性要求较高使用
std::mt19937
作为引擎
#include <random>
#include <iostream>int main() {// 指定种子std::mt19937 engine(std::random_device{}());int count = 10;// 指定范围:整数std::uniform_int_distribution<int> rand_int_generator(0, 100);for (int i=0; i<10; ++i) {std::cout << "int random value:" << rand_int_generator(engine) << std::endl;}// 指定范围:浮点数std::uniform_real_distribution<double> rand_double_generator(0, 1);for (int i=0; i<10; ++i) {std::cout << "double random value:" << rand_double_generator(engine) << std::endl;}
};
3. Mersenne Twister (马特赛特旋转算法)
3. 1工作原理:
Mersenne Twister 算法维护一个内部状态向量,这个向量的长度通常为 n个w -bit 的字。对于最常见的
MT19937
版本,n=624且w=32
- 初始化
- 首先使用一个种子(可以是任意整数)初始化内部状态向量。通常会对种子进行一些处理,将其扩展到内部状态向量的长度
- 状态更新
- 通过一个复杂的位操作函数对状态向量进行更新,这个函数被称为 “twist” 操作。在
MT19937
中,它使用了一系列的移位、异或和与操作,将状态向量中的元素进行混合和更新 - 经过多次 “twist” 操作,状态向量中的元素会以一种复杂的方式发生变化,保证了下一个随机数的不可预测性
- 通过一个复杂的位操作函数对状态向量进行更新,这个函数被称为 “twist” 操作。在
- 随机数提取
- 从更新后的状态向量中提取随机数。通常使用一个函数将状态向量中的元素映射到所需的输出范围。例如,对于生成 32 位的随机数,直接使用状态向量中的元素,而对于生成小于 32 位的随机数,则会对状态向量中的元素进行适当的截断或位操作来生成所需的随机数
3.2 特点:
- 长周期
- Mersenne Twister 的周期通常是 2^19937-1,这是一个巨大的数字,使得生成的随机数序列非常长,能够避免在实际应用中出现周期短导致的重复序列问题
- 高维均匀分布
- 生成的随机数在高维空间中具有良好的均匀分布特性,这对于需要多个随机数进行模拟或计算的情况非常重要
- 随机性质量高
- 通过复杂的位操作和状态转移函数来产生随机数,克服了一些简单随机数生成器(如线性同余发生器)的缺点,如生成的随机数序列的可预测性和低质量