Loading

Boost随机库的简单使用:Boost.Random(STL通用)

文章目录


文章内容介绍

Boost.Random是Boost里面的一个随机库,它的第一正式版是在Boost 1.15中提供。它里面提供了大量的随机算法,比如mt19937算法,加权概率,随机密码等。可以很方便的提高编码效率。

本文主要介绍了Boost.Random的一些简单使用本文主要分为四个部分,第一部分为此简单介绍,第二部分为Boost.Random的使用,第四部分为总结。

本文参考的Boost版本为1.74。

Boost随机库的简单使用

生成一个随机的整数

boost::random::mt19937 gen(time((time_t *)NULL));
std::cout << gen() << std::endl;

首先构造一个随机数生成器,这里我们使用mt19937算法的随机数生成器。然后直接将随机数生成器作为一个函数对象使用,便可以得到一个区间为\([0, 2^{32}-1]\)的随机数。

如果要生成64位的随机数,可以使用boost::random:mt19937_64。相应的,它可以产生区间为\([0, 2^{64}] - 1\)的随机数。

除了mt19937算法以外,Boost.Random还提供了非常多种的平均随机数算法,譬如minstd_rand0minstd_randrand48ecuyer1988knuth_b等。

除了使用算法生成一个伪随机数外,Boost还提供了一个接口random_device,可以产生真·随机数。它依赖于系统提供的硬件随机,比如在Linux下会使用/dev/urandom。理论上来说,提供的硬件随机应该是不会产生错误,或者读取到结尾的。如果发生了,便会抛出std::io_base::failure异常。使用entropy方法可以获得随机数生成器的熵值。

生成一个区间的平均概率随机数

一般情况下,我们都是需要生成一个区间内的随机数,这才有一定的使用价值。在C语言中,我们通过以下方法获得

rand()%(upper_bound - lower_bound) + lower_bound

而在Boost中,它为我们提供了一个方法,可以通过定义分布的方法,来生成一个区间的随机整数。

boost::random::uniform_int_distribution<> dis(1, 6);
std::cout << dis(gen) << std::endl;  

首先我们定义了一个分布,从这个类的名称我们就可以知道,这是一个平均的整数分布。分布和生成器一样,是一个函数对象,通过输入一个随机数生成器,就可以得到随机区域内的整数。生成的范围为\([min, max]\)

生成随机实数也是类似,生成的范围为\([min, max)\)

boost::random::uniform_real_distribution<> fdis(0, 2);
std::cout << fdis(gen) << std::endl;

除了这些比较常用的平均分布外,Boost还提供了两种使用次数比较多的平均分布:

  1. uniform_smallint,它和uniform_int_distribution类似,不过这个分布要求生成的范围要远小于随机数生成器的范围;
  2. uniform_01 产生\([0, 1)\)之间的随机数。

按概率生成一个区间的随机整数

这种情况如果使用C语言实现,一般会是这样操作。

// 选择的概率,选择的数据为[0,3]
double prob = {0.1, 0.2, 0.3, 0.4};

double choose_prob = (random() % 100000)/100000.0;

choosed_number = 0;
for (choosed_number = 0; choosed_number < 4; ++choosed_number) {
    choose_prob -= prob[choosed_number];
    if (choose_prob < 0) break;
}

此时,choosed_number为选择的数据。在Boost.Random中,提供了更为优雅的方法,来实现这一操作。

boost::random::discrete_distribution<> prob_dis({0.1, 0.2, 0.3, 0.4});
std::vector<int> count(4, 0);
for (int loop_i = 0; loop_i < 100000; ++loop_i) {
  count[prob_dis(gen)]++;
}

for (int loop_i = 0; loop_i < 4; ++loop_i) {
  std::cout << count[loop_i] << ",";
}
std::cout << std::endl;

为了更好的表现数据的分布,我使用了一个计数器,来对10万次实验的结果进行统计。得到结果如下:

可以看到结果的分布和我们设置的概率相近。

当然,部分的时候,我们设置的并不是概率(和为一),而是权重(和可能不为一),这个在discrete_distribution中也是可行的,也就是:

boost::random::discrete_distribution<> prob_dis({1, 2, 3, 4});

是可行的,而且它们的结果是一致的。

除此之外,还可以通过Boost.range和函数来设置不同的概率。

一些经典的分布

除了自定义分布外,Boost还提供了许多的经典分布,只需要通过简单的参数设置就可以获得一些经典的分布器。

  1. 伯努利分布

伯努利分布又称为0-1分布,结果只有0或者1。

  1. 泊松分布

泊松分布适合于描述单位时间内随机事件发生的次数的概率分布。如某一服务设施在一定时间内受到的服务请求的次数,电话交换机接到呼叫的次数、汽车站台的候客人数、机器出现的故障数、自然灾害发生的次数、DNA序列的变异数、放射性原子核的衰变数、激光的光子数分布等等。

  1. 正态分布

正态分布又名高斯分布,是一个非常常见的连续概率分布。正态分布在统计学上十分重要,经常用在自然和社会科学来代表一个不明的随机变量。

与STL的对比

STL作为C++的标准库,里面也包含有Random库。根据我的查阅的资料,他们之间的借口大部分是相同的,不过也有一小部分的差异。譬如:

  1. default_random_engine

STL提供了一个default_random_engine。但是这个随机数生成器并不好用,也需要输入一个种子,而且当种子相近的时候,其值也非常相近。个人认为随机性并不是特别好。

  1. random_drive

STL和Boost.Random中的硬件随机数生成器描述相近,但是在我个人实际的使用中,Boost.Random给出的熵值为10(部分使用随机?),STL给出的熵值为0(完全使用随机算法)。

Ref

博客原文地址:https://www.cnblogs.com/ink19/p/Boost_Random.html

posted @ 2020-12-05 11:44  ink19  阅读(1570)  评论(0编辑  收藏  举报