C++中的随机数

在C++中有两种获得随机数的方法,一个是位于<cstdlib>中的rand函数,一个是C++11中引入的<random>。

rand函数

rand 函数返回一个int类型的整数,其值位于0至RAND_MAX之间(包含两端)。其中,RAND_MAX依赖于库的实现,保证至少为32767。经过测试,这个值在VS 2015以及MinGW gcc 7中均为32767,而在Ubuntu 64bit gcc 中为2147483647。一般来说,可以使用以下方式获取随机数:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
    // 获取10个随机数
    for(int i = 0; i < 10; i++)
        cout << rand() << endl;
}

实验发现,每次执行上述代码都产生相同的序列。这是因为这种获取随机数的方式产生的是伪随机数,每次执行代码前,随机数的种子都相同,因此获得的随机数序列也相同,为了获得不同的随机数序列,可以为随机数设置不同的种子。

由于相同的随机数种子产生相同的随机数序列,因此通常采用将当前的系统时间作为随机数种子,这样每次运行时随机数种子一般都不相同。

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main() {
    // 设置随机数种子
    srand((unsigned)time(nullptr));
    // 产生10个随机数
    for(int i = 0; i < 10; i++)
        cout << rand() << endl;
}

<random>

由于种种原因,采用rand函数产生的随机数在随机性上有一定的缺陷,对于严格的需求,不建议采用rand来获取随机数,而是使用C++11中引入的random。

一个简单的获取随机数的方法是使用random_device类。这是一个生成均匀分布的随机数的生成器,假如有可用的可以产生真随机数的硬件设备,random_device将产生真随机数序列,如果没有用于产生真随机数的设备,则采用伪随机数的方式实现。random_device生成unsigned类型的随机数,一般情况下介于0与4294967295之间。

#include <iostream>
#include <random>
using namespace std;

int main() {
    random_device rd;
    // 产生10个随机数
    for(int i = 0; i < 10; i++) {
        cout << rd() << endl;
    }
}

一般来说,每次执行上述代码应该产生不同的随机数序列,但在测试MinGW时,每次产生的序列都相同,这应该是它的一个BUG。

虽然random_device可以获取真随机数,但由于其受产生随机数的硬件限制,所以一般用于为伪随机数引擎生成种子。C++标准库实现了linear_congruential_engine(线性同余算法),mersenne_twister_engine(梅森缠绕器算法)以及subtract_with_carry_engine(带进位减算法)等随机数引擎以及discard_block_engine,independent_bits_engine,shuffle_order_engine等适配器,以及基于这些引擎和适配器而定义的随机数生成器,例如:mt19937,mt19937_64,knuth_b等。可以采用以下方法使用随机数生成器。

#include <iostream>
#include <random>
using namespace std;

int main() {
    random_device rd;
    mt19937 mt(rd());
    // 产生10个随机数
    for(int i = 0; i < 10; i++) {
        cout << mt() << endl;
    }
}

除了随机数引擎外,C++还提供了获取服从不同分布的随机数的方法,例如均匀分布、伯努利分布、泊松分布、正态分布等。此处以均匀分布为例展示使用方法。

#include <iostream>
#include <random>
using namespace std;

int main() {
    random_device rd;
    mt19937 mt(rd());
    // 产生位于[1, 100]间的随机数
    uniform_int_distribution<int> randint(1, 100);
    for(int i = 0; i < 5; i++)
        cout << randint(mt) << ' ';
    cout << endl;
    // 产生位于[0.2, 0.8)间的随机数,注意区间
    uniform_real_distribution<double> randdouble(0.2, 0.8);
    for(int i = 0; i < 5; i++)
        cout << randdouble(mt) << ' ';
    cout << endl;
}

C++中提供的获取随机数的方法可以满足大部分需求,对于生成一般的随机数,建议使用随机数引擎(如mt19937等),生成某个区间的随机数则根据需要选择不同的分布(如uniform_int_distribution等),出于实用性考虑不建议使用rand函数产生随机数。

One Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注