随机数
- [1. Qt](#1. Qt)
-
- [1.1 qsrand() 和qrand()](#1.1 qsrand() 和qrand())
- [1.2 QRandomGenerator 类](#1.2 QRandomGenerator 类)
- [2. C语言](#2. C语言)
-
- [2.1 使用 rand() 和 srand() 函数](#2.1 使用 rand() 和 srand() 函数)
- [2.2 使用 <random.h> 库(C11 标准)](#2.2 使用 <random.h> 库(C11 标准))
- [3. C++](#3. C++)
-
- [3.1 使用 <cstdlib> 和 <ctime> 库(旧方法)](#3.1 使用 <cstdlib> 和 <ctime> 库(旧方法))
- [3.2 使用 <random> 库(C++11 及以后推荐方法)](#3.2 使用 <random> 库(C++11 及以后推荐方法))
- [3.3 生成浮点数随机数](#3.3 生成浮点数随机数)
1. Qt
1.1 qsrand() 和qrand()
通过qsrand() 和qrand()函数来生成随机数。随机数生成器本质上是按照特定算法生成一系列看似随机的数字。但实际上,这些数字是基于一个初始值(即种子)按照固定算法计算得出的。如果每次使用相同的种子,那么随机数生成器将产生相同的随机数序列。qsrand() 函数的作用就是为随机数生成器设置这个初始种子,从而影响后续生成的随机数序列。
- qsrand() 是 Qt 框架提供的一个用于初始化随机数生成器种子的函数,它在<QtCore/QRandomGenerator> (旧版本中是 <QtCore/QTime> 配合使用)相关的随机数生成操作中扮演着重要角色。
该函数在 <QtCore/QRandomGenerator> 头文件(在旧版本中为 <QtCore/QCoreApplication> )中声明。这里的参数 seed 是一个无符号整数,作为随机数生成器的种子。
cpp
void qsrand(uint seed);
- qrand() 函数用于生成具体的随机数。qrand() 函数用于生成伪随机整数。该函数生成的随机数范围是 [0, RAND_MAX],其中 RAND_MAX 是一个常量,表示随机数的最大值。RAND_MAX 的值在不同的系统和编译器中可能会有所不同,但在大多数系统中,RAND_MAX 被定义为 32767 (即 2^15 - 1)。这意味着 qrand() 函数生成的随机数是一个非负整数,其取值范围从 0 到 RAND_MAX。
cpp
#include <QCoreApplication>
#include <QDebug>
#include <QTime>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 使用当前时间作为种子初始化随机数生成器
qsrand(QTime::currentTime().msec());
// 生成并输出10个随机整数
for (int i = 0; i < 10; ++i) {
int randomNumber = qrand();
qDebug() << "生成的随机数: " << randomNumber;
}
return a.exec();
}
在这个例子中,使用 QTime::currentTime().msec() 作为种子,因为每毫秒的时间值通常是不同的,所以每次运行程序时,随机数生成器的种子不同,进而产生不同的随机数序列。qrand() 函数用于生成具体的随机数。
1.2 QRandomGenerator 类
不过,在现代 Qt(Qt 5.10 及以后版本)中,推荐使用 QRandomGenerator 类来生成随机数,它提供了更安全、更现代的随机数生成方式,而 qsrand() 和 qrand() 已被标记为过时。示例如下:
cpp
#include <QCoreApplication>
#include <QDebug>
#include <QRandomGenerator>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 生成并输出10个随机整数
for (int i = 0; i < 10; ++i) {
quint32 randomNumber = QRandomGenerator::global()->generate();
qDebug() << "生成的随机数: " << randomNumber;
}
return a.exec();
}
在这个示例中,QRandomGenerator::global()->generate() 用于生成一个无符号 32 位整数的随机数,并且不需要手动设置种子,QRandomGenerator 会自动处理种子的初始化,提供更好的随机性和安全性。
QRandomGenerator::global()->bounded(0, 101) 用于生成一个范围在 [0, 100] 的随机整数
- 可重复性问题:如果需要复现相同的随机数序列,可使用固定的种子调用 qsrand()。但在大多数实际应用场景中,为了得到不同的随机数序列,通常会使用变化的值(如当前时间)作为种子。
- 过时性:由于 qsrand() 和 qrand() 存在一些随机性和安全性方面的问题,在新的 Qt 项目中建议使用 QRandomGenerator 类来替代。
2. C语言
2.1 使用 rand() 和 srand() 函数
- rand() 函数:该函数会返回一个介于 0 到 RAND_MAX 之间的伪随机整数。RAND_MAX 是一个常量,其值至少为 32767,不同系统可能会有所不同。
- srand() 函数:此函数用于初始化随机数生成器的种子。若每次运行程序时种子相同,rand() 函数就会生成相同的随机数序列。所以,通常会使用当前时间作为种子,以确保每次运行程序时生成不同的随机数序列。
c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
// 使用当前时间作为随机数生成器的种子
srand(time(NULL));
// 生成10个随机数
for (int i = 0; i < 10; i++) {
// 生成一个0到99之间的随机数
int random_num = rand() % 100;
printf("随机数 %d: %d\n", i + 1, random_num);
}
return 0;
}
- srand(time(NULL)):time(NULL) 会返回当前的时间戳,将其作为 srand() 函数的参数,以此初始化随机数生成器的种子。
- rand() % 100:rand() 函数生成一个随机整数,通过取模运算 % 100 可以将随机数的范围限制在 0 到 99 之间。
2.2 使用 <random.h> 库(C11 标准)
C11 标准引入了 <random.h> 库,该库提供了更强大、更灵活的随机数生成功能,能够生成不同分布的随机数,如均匀分布、正态分布等。
c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <random>
int main() {
// 创建一个随机数生成器
struct random_data rd;
char state[32];
initstate_r(time(NULL), state, sizeof(state), &rd);
// 生成10个0到99之间的随机数
for (int i = 0; i < 10; i++) {
int random_num;
random_r(&rd, &random_num);
random_num = random_num % 100;
printf("随机数 %d: %d\n", i + 1, random_num);
}
return 0;
}
- initstate_r():该函数用于初始化随机数生成器的状态,使用当前时间作为种子。
- random_r():此函数会生成一个随机整数,同样通过取模运算将随机数的范围限制在 0 到 99 之间。
- random_data 结构体是 <random.h> 头文件里定义的,这个头文件是 C11 标准引入的,用于实现更高级的随机数生成功能。random_data 结构体用于存储随机数生成器的内部状态信息。在使用 random_r 这类可重入的随机数生成函数时,就需要借助这个结构体来保存和管理随机数生成器的状态。之所以要有这样的结构体,是因为可重入函数要能在多线程环境下安全使用,每个线程得有自己独立的随机数生成器状态,避免不同线程之间的状态相互干扰。
- 状态数组:char state[32]; 定义了一个字符数组 state,用于存储随机数生成器的状态信息。
- 在多线程环境中使用 random_r 函数时,每个线程都需要有自己独立的 random_data 结构体变量,以此保证线程安全。
3. C++
3.1 使用 和 库(旧方法)
这种方法主要利用 rand() 函数生成随机数,同时使用 srand() 函数设置随机数种子。rand() 函数会返回一个介于 0 到 RAND_MAX 之间的伪随机整数,RAND_MAX 是一个常量,其值至少为 32767。为了让每次运行程序时生成不同的随机数序列,通常会使用 srand() 结合 time() 函数以当前时间作为种子。
cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
int main() {
// 使用当前时间作为随机数种子
std::srand(static_cast<unsigned int>(std::time(nullptr)));
// 生成10个0到99之间的随机数
for (int i = 0; i < 10; ++i) {
int randomNumber = std::rand() % 100;
std::cout << "随机数 " << i + 1 << ": " << randomNumber << std::endl;
}
return 0;
}
- std::srand(static_cast(std::time(nullptr)));:使用当前时间作为随机数种子,确保每次运行程序时生成不同的随机数序列。
- std::rand() % 100:生成一个 0 到 99 之间的随机数。
3.2 使用 库(C++11 及以后推荐方法)
库是 C++11 引入的,提供了更强大、更灵活且随机性更好的随机数生成功能。它包含了多种随机数引擎和分布类型,可以根据需求选择合适的引擎和分布来生成随机数。
cpp
#include <iostream>
#include <random>
int main() {
// 定义随机数引擎,这里使用默认的随机数引擎
std::random_device rd;
std::mt19937 gen(rd());
// 定义分布类型,这里使用均匀分布,范围是0到99
std::uniform_int_distribution<> dis(0, 99);
// 生成10个随机数
for (int i = 0; i < 10; ++i) {
int randomNumber = dis(gen);
std::cout << "随机数 " << i + 1 << ": " << randomNumber << std::endl;
}
return 0;
}
- std::random_device rd;:创建一个 random_device 对象,它通常用于获取真正的随机数种子。
- std::mt19937 gen(rd());:创建一个 mt19937 随机数引擎,并使用 random_device 生成的种子进行初始化。mt19937 是一个常用的梅森旋转算法随机数引擎,具有较好的随机性和性能。
- std::uniform_int_distribution<> dis(0, 99);:创建一个均匀整数分布对象,指定随机数的范围为 0 到 99。
- dis(gen):通过分布对象 dis 对随机数引擎 gen 进行采样,生成一个符合指定分布的随机数。
3.3 生成浮点数随机数
使用 库也可以方便地生成浮点数随机数,以下是一个生成 0 到 1 之间浮点数随机数的示例:
cpp
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
// 定义均匀浮点分布,范围是0到1
std::uniform_real_distribution<> dis(0.0, 1.0);
for (int i = 0; i < 10; ++i) {
double randomNumber = dis(gen);
std::cout << "随机浮点数 " << i + 1 << ": " << randomNumber << std::endl;
}
return 0;
}
这个示例与生成整数随机数的示例类似,只是使用了 std::uniform_real_distribution 来定义浮点数的均匀分布。