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用于生成正态分布的随机数。分布函数需要结合生成器使用,从而生成具有特定分布特征的随机数。

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

目录
相关文章
|
19天前
|
算法 安全 编译器
【C++ 泛型编程 进阶篇】C++模板参数推导的场景分析
【C++ 泛型编程 进阶篇】C++模板参数推导的场景分析
61 0
【C++ 泛型编程 进阶篇】C++模板参数推导的场景分析
|
19天前
|
算法 程序员 C语言
【C++ 随机数分布类型 】深入探索C++随机数分布:原理、应用与实践(二)
【C++ 随机数分布类型 】深入探索C++随机数分布:原理、应用与实践
64 0
【C++ 随机数分布类型 】深入探索C++随机数分布:原理、应用与实践(二)
|
19天前
|
存储 Java 编译器
java和c++的主要区别、各自的优缺点分析、java跨平台的原理的深度解析
java和c++的主要区别、各自的优缺点分析、java跨平台的原理的深度解析
159 0
|
19天前
|
存储 自然语言处理 算法
【编译原理】LR(1)分析法:C/C++实现
【编译原理】LR(1)分析法:C/C++实现
383 0
|
19天前
|
算法 安全 大数据
【C/C++ 随机函数行为】深入探索C++中的随机数:std::random_device与rand的行为分析(二)
【C/C++ 随机函数行为】深入探索C++中的随机数:std::random_device与rand的行为分析
67 0
|
2天前
|
存储 程序员 编译器
C/C++堆栈详细分析,新老程序员必会
C/C++堆栈详细分析,新老程序员必会
11 1
|
19天前
|
C++
N诺——c++取随机数
N诺——c++取随机数
20 0
|
19天前
|
存储 程序员 编译器
c++面向对象概述、内存分析、引用、函数
c++面向对象概述、内存分析、引用、函数
|
19天前
|
算法 Java C++
【C/C++ 内存知识扩展】内存不足的可能性分析
【C/C++ 内存知识扩展】内存不足的可能性分析
14 0
|
19天前
|
存储 监控 Linux
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
55 0