C++11 的随机数的分析

简介: C++11 的随机数的分析

C++11 是一个比较重要的版本,它引入了许多新的语言特性和标准库组件。其中,随机数生成的新特性极大地方便了开发人员在程序中生成随机数。

C++11 的随机数生成分为三个层次,包括随机数生成设备、随机数引擎和随机分布。下面分别对它们进行介绍。


产生随机数


C++11 的标准库提供了一个非确定性随机数生成设备,即 std::random_device。在 Linux 系统中,std::random_device 通过读取 /dev/urandom 设备来产生真随机数;而在 Windows 系统中,std::random_device 通过 rand_s 函数来产生伪随机数。使用 std::random_device 产生随机数时,可以通过调用其 operator() 方法返回一个 min()max() 之间的随机数。


#include <iostream>
#include <random>
int main()
{
  std::random_device rd;
  for(int n=0; n<20000; ++n)
    std::cout << rd() << std::endl;
  return 0; 
}


随机数引擎


随机数引擎是一种伪随机数生成器,传入一个种子后,根据种子生成随机数。C++11 标准提供了三种常用的随机数引擎:std::linear_congruential_enginestd::mersenne_twister_enginestd::subtract_with_carry_engine。其中,std::linear_congruential_engine 是最常用的一种,速度也非常快;std::mersenne_twister_engine 则被称为最好的伪随机数生成器;std::subtract_with_carry_engine 目前还不太清楚。

使用随机数引擎时,可以通过传入一个整型参数作为种子,也可以使用默认值。如果想多次运行产生相同的随机数,可以使用一个确定的数作为种子;如果想每次运行生成不一样的随机数,则建议使用 std::random_device 产生一个随机数作为种子(Linux 下为真随机数,Windows 下为伪随机数)。

下面是一个示例代码,用于输出 10 个随机数:


#include <iostream>
#include <random>
int main()
{
  std::random_device rd;
  std::mt19937 mt(rd());  // 梅森旋转算法
  for(int n = 0; n < 10; n++)
    std::cout << mt() << std::endl;
  return 0;
}


随机分布


STL 标准库还提供各种各样的随机分布,不过我们经常用的比较少,比如平均分布,正太分布…使用也很简单。随机分布是利用一定的算法处理 URBG 的输出,以使得输出结果按照定义的统计概率密度函数分布。


//平均分布
#include <random>
#include <iostream>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(1, 6);
    for(int n=0; n<10; ++n)
        std::cout << dis(gen) << ' ';
    std::cout << '\n';
}


我们使用 std::random_device 生成种子,以防止使用相同的种子而导致每次程序运行生成相同的随机数序列。接着使用 std::mt19937 作为随机数引擎,生成均匀分布。最后,使用循环输出生成的随机数。


//正太分布
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <cmath>
int main()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    // values near the mean are the most likely
    // standard deviation affects the dispersion of generated values from the mean
    std::normal_distribution<> d(5,2);
    std::map<int, int> hist;
    for(int n=0; n<10000; ++n) {
        ++hist[std::round(d(gen))];
    }
    for(auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}


我们使用 std::normal_distribution 生成正态分布。其中,分布的期望为5,标准差为2。使用循环生成10000个随机数,并将每个数四舍五入到最接近的整数。接着使用 std::map 计算每个数出现的次数,并输出直方图。


总结和思考


我们对于随机数生成器,可以选择使用std::random_device作为种子,来保证生成的随机数更加随机。使用std::mt19937作为生成器,并结合不同的分布函数,可以生成不同类型的随机数。需要注意的是,在生成器初始化时,需要将种子传入生成器中。

对于分布函数,C++标准库提供了多种分布函数,如std::uniform_int_distribution用于生成均匀分布的整数,std::normal_distribution用于生成正态分布的随机数。分布函数需要结合生成器使用,从而生成具有特定分布特征的随机数。

我们在使用随机数生成器和分布函数时,需要考虑生成的随机数的范围和分布情况,以及生成的随机数是否满足要求。在进行模拟和实验时,随机数的质量直接影响着结果的准确性和可靠性。

目录
相关文章
|
27天前
|
存储 自然语言处理 算法
【编译原理】LR(1)分析法:C/C++实现
【编译原理】LR(1)分析法:C/C++实现
41 0
|
4月前
|
安全 C++ 开发者
C++ const分析
C++ const分析
24 0
|
2月前
|
存储 C++ 容器
[C++ 从入门到精通] 5.迭代器精彩演绎、失效分析及弥补、实战
[C++ 从入门到精通] 5.迭代器精彩演绎、失效分析及弥补、实战
26 0
|
1月前
|
固态存储 数据安全/隐私保护 计算机视觉
C++医院影像科PACS源码:三维重建、检查预约、胶片打印、图像处理、测量分析等
C++医院影像科PACS源码:三维重建、检查预约、胶片打印、图像处理、测量分析等
34 0
|
2月前
|
算法 测试技术 C#
C++二分算法:黑名单中的随机数
C++二分算法:黑名单中的随机数
|
3月前
|
C++
《C++避坑神器·二》引用的本质分析
《C++避坑神器·二》引用的本质分析
28 0
|
4月前
|
编译器 程序员 C语言
【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)
【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)
|
5月前
|
C++
如何在C++中生成随机数
在C++中,生成随机数是一个常见的技术需求。本文将介绍如何在C++中使用标准库来生成随机数。
89 0
|
6月前
|
信息无障碍 C++
万字长文,深度分析 c++的前景
万字长文,深度分析 c++的前景
69 0
|
8月前
|
安全 C++
c++的queue在多线程下崩溃原因分析
c++的queue在多线程下崩溃原因分析