首页 > 其他分享 >std::mt19937使用指北

std::mt19937使用指北

时间:2022-10-16 14:11:29浏览次数:85  
标签:std 指北 mt19937 int 生成 分布 distribution

这东西的名字名字很怪(全名应该叫maxint2^19937-1)。

作为C++语言里的东西,它的作用是用来生成随机数。

I

我们不妨从这东西的原理开始说起。

它位于的C++头文件为 #include<random>
在这个头文件里,有着这么一些话:

/**
   * A generalized feedback shift register discrete random number generator.
   *
   * This algorithm avoids multiplication and division and is designed to be
   * friendly to a pipelined architecture.  If the parameters are chosen
   * correctly, this generator will produce numbers with a very long period and
   * fairly good apparent entropy, although still not cryptographically strong.
   *
   * The best way to use this generator is with the predefined mt19937 class.
   *
   * This algorithm was originally invented by Makoto Matsumoto and
   * Takuji Nishimura.
   *
   * balabala...
   */

大致意思:
这是一个线性反馈移位寄存器,用梅森旋转算法实现,该算法无需乘除,如果选择的种子正确,该算法生成的数字周期会很长,但是还不够强(自谦)。

使用这个算法的最佳方式是使用预定义的std::mt19937类。

也就是这个东西:

std::mersenne_twister_engine<std::uint_fast32_t, 32, 624, 397, 31,
                             0x9908b0df, 11,
                             0xffffffff, 7,
                             0x9d2c5680, 15,
                             0xefc60000, 18, 1812433253>

这就是 std::mt19937

这个是 std::mt19937_64

std::mersenne_twister_engine<std::uint_fast64_t, 64, 312, 156, 31,
                             0xb5026f5aa96619e9, 29,
                             0x5555555555555555, 17,
                             0x71d67fffeda60000, 37,
                             0xfff7eee000000000, 43, 6364136223846793005>

random.h中:

template<
    class UIntType,
    std::size_t w, std::size_t n, std::size_t m, std::size_t r,
    UIntType a, std::size_t u, UIntType d, std::size_t s,
    UIntType b, std::size_t t,
    UIntType c, std::size_t l, UIntType f
> class mersenne_twister_engine;

II

我们知道,rand作为一个随机数生成器,它的性能是不够强。

它所对应的 RAND_MAX 范围不过在 32767(short型的最大值) 到 2147483647(int型的最大值)之间,如果生成更大的数字(用rand()*rand()之类的东西)并不均匀,速度也不够快,所以我们可以用到 std::mt19937std::mt19937_64 两个东西来生成一个比较大的数字(毒瘤出题人狂喜)。

由于它所生成的数在最大到 \(2^{19937}-1\),我们可以把它的范围看作无限制。

III

使用之前,我们知道,作为一个伪随机数生成器,它需要一个种子。这就好比rand()需要srand()一样。

那我们怎么播种子呢(不写种子,直接用默认的)?

比较常见的方法是使用ctime.h里的time(0),用这个函数返回的秒数作为一个种子:

mt19937 example(time(0))

这样我们就选好了种子,接下来直接使用就可以了

cout<<example()<<'\n';

发现这样生成的数相当均匀,质量也相当高。

你觉得这种做法不够精妙,你觉得以秒为单位似乎不是很好。

怎么办?

C++里还有另外一个东西 std::random_device,这个东西呢,在linux系统下是按照熵池来生成的,“在熵池耗尽前可以高速生成随机数”。

不知道什么人出了用 std::random_devicestd::mt19937 生成种子的奇怪招数:

int main()
{
    random_device seeds;
    mt19937 example(seeds());
    cout << example() << endl;
    return 0;
}

这么写也是可以的(time(0)不可以):

int main()
{
    random_device seeds;
    
    for(int i=1;i<=20;i++)
    {
    	mt19937 example(seeds());
        cout << example() << endl;
    }
    return 0;
}

IV

我们随机去生成指定区间内的数字。
这里又要用到另一个东西:std::uniform_int_distribution
它的作用呢,是去生成随机区间的,用法:

std::uniform_int_distribution<> exp(l,r)

我们传入参数,它就可以去形成 \([l,r]\) 之间的整数。
更具体的:

int main()
{
    mt19937 example(time(0));
    uniform_int_distribution<> distrib(114,514);
    for (int i=1; i<=10;i++)
    {
    	cout<<distrib(example)<<' ';
    }
    return 0;
}

由于成员函数(随机数引擎)的关系,它需要传入一个 std::mt19937 即梅森缠绕器(mersenne_twister_engine) 来使用。

V

我个人用的大概如下:

  1. uniform_real_distributionuniform_int_distribution 这两个属于均匀分布,前者可以生成均匀分布的实数,后者生成均匀分布的整数。
  2. bernoulli_distribution 用于产生 \(bernoulli\) 分布上的 bool 数。用法:
int main()
{
    mt19937 example(time(0));
    bernoulli_distribution distrib;
    for (int i=1; i<=100;i++)
    {
    	cout<<distrib(example)<<' ';
    }
    return 0;
}

生成100个随机的 bool数(性能高)。

  1. normal_distribution,创建一个有特定期望值和方差的正态分布。传入的两个值是期望和方差。
int main()
{
    mt19937 example(time(0));
    normal_distribution<double> distrib(5,6);
    for (int i=1; i<=100;i++)
    {
    	cout<<distrib(example)<<' ';
    }
    return 0;
}

生成随机实数。

  1. generate_canonical,指定位数生成随机的,\([0,1)\) 之间的实数。传入两个值是类型和最后的 \(bit\) 位。
int main()
{
    mt19937 example(time(0));
    for (int i=1; i<=100;i++)
    {
    	cout<<generate_canonical<double,50>(example)<<' ';
    }
    return 0;
}

VI

关于这个东西,前边的日报有讲,感兴趣可以看不感兴趣只用不看

更多的一些随机数分布:

函数名称 分布类型 作用
uniform_int_distribution<> (x,y) 均匀分布 产生一定范围内的整数
uniform_real_distribution<> (x,y) 均匀分布 产生一定范围内的实数
bernoulli_distribution 伯努利分布 产生伯努利分布上的 bool
binomial_distribution<> (x,y) 伯努利分布 产生二项分布上的整数值
negative_binomial_distribution<> (x,y) 伯努利分布 产生负二项分布上的的整数值
geometric_distribution<> 伯努利分布 产生几何分布上的的整数值
poisson_distribution<> (x) 泊松分布
exponential_distribution<> (x) 泊松分布 产生指数分布上的实数值。
gamma_distribution<> (x,y) 泊松分布 产生伽马分布上的实数值
weibull_distribution 泊松分布 产生威布尔分布上的实数值。
normal_distribution<> {x,y} 正态分布 产生标准正态分布上的实数值。
lognormal_distribution<> (x,y) 正态分布 产生对数正态分布上的实数
discrete_distribution<> {(w,x,y,z)} 采样分布 产生离散分布上的随机整数。

VII

这些东西需要在 C++11及以上标准中使用。

编译时请自行更改标准。

标签:std,指北,mt19937,int,生成,分布,distribution
From: https://www.cnblogs.com/SoN3ri/p/CCF_NMSL_WCNMD.html

相关文章

  • 实现fastdfs防盗链功能
    1、背景我们可以通过fastdfs实现一个分布式文件系统,如果我们的fastdfs部署在外网,那么任何一个人知道了我们的上传接口,那么它就可以文件的上传和访问。那么我们如何阻止他人......
  • python学习:获取指定目录下所有文件名os.walk和os.listdir
    1.os.walk返回指定路径下所有文件和子文件夹中所有文件列表其中文件夹下路径如下:importosdeffile_name_walk(file_dir):forroot,dirs,filesinos.walk(f......
  • NodeJS 服务 Docker 镜像极致优化指北
    这段时间在开发一个腾讯文档全品类通用的HTML动态服务,为了方便各品类接入的生成与部署,也顺应上云的趋势,考虑使用Docker的方式来固定服务内容,统一进行制品版本的管理。......
  • std::vector 的使用
    std::vector是物理存储空间连续、无需指定大小、自动扩容的动态数组,并提供了丰富的API。初练添加元素(末尾):push_back删除元素(末尾):pop_back获取元素个数:size遍历方法......
  • 安装pyflink1.15.2报错[gcc: error: unrecognized command line option '-std=c++14']
    问题描述:安装一些pyflink1.15.2时报错:gcc:error:unrecognizedcommandlineoption‘-std=c++14’ 解决方案升级gcc版本为5.2.0升级g++版本为5.2.0实施步骤cd/us......
  • FastDfs操作
    FastDfs安装准备libfastcommon-1.0.48.tar.gzfastdfs-6.07.tar.gzlibfastcommon-1.0.48.tar.gzfastdfs-6.07.tar.gz安装gcc环境yuminstall-ygccgcc-c++开始......
  • FastDFS
    一、FastDFS简介FastDFS是一个轻量级的开源分布式文件系统,纯C实现,所以在Linux中部署时要引入C语言包主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载......
  • vscode include<stdio.h>头文件红色的解决办法
    原因是标准库没识别到。前提需要安装c/c++插件第一步:点击下面win按钮,选择配置JSON第二步:打开c_cpp_properties.json,添加include路径,放在最上面......
  • 实现fastdfs防盗链功能
    目录1、背景2、实现原理2.1开启防盗链2.2重启nginx2.3Java代码生成token1、token生成规则2、java生成token3、测试3.1带正确token访问3.2带错误token访问4、项目代码......
  • OpenHarmony命令行调试工具hdc_std介绍
    今天有人问dayu200可以用hdc工具吗?突然发现,我还没用过,于是就有了这篇文章hdc_std是什么?hdc_std是OpenHarmony提供的用于调试的命令行工具,通过该工具可以在Windows/Linux等系......