[转]C++11 随机数学习
相对于C++ 11之前的随机数生成器来说,C++11的随机数生成器是复杂了很多。这是因为相对于之前的只需srand、rand这两函数即可获取随机数来说,C++11提供了太多的选择和东西。
随机数生成算法:
随机数生成算法有很多,C++11之前的C/C++只用了一种。C++11则提供下面三种可供选择:
linear_congruential_engine线性同余法
mersenne_twister_engine梅森旋转法
substract_with_carry_engine滞后Fibonacci
这三种算法,在C++11里面都是用模板的方式实现的。如果我们要使用这三个模板类的话,就必须自己实例化之。但这些实例化参数都是这些算法里面使用到的参数,如果不懂算法的原理的话,真的不知道需要用什么参数才能得到比较好的随机序列。所以我们这些卑微的码农是用不了这些模板类的。C++11标准也想到了这点,所以就帮我们预定义了一些随机数类,这些随机数类都是用比较好的参数实例化上面那三个模板类。注意:在C++11里面,把这些随机数生成器叫做引擎(engines)。
下图列出了一些实例化的随机数类:
当然具体用了哪些参数,我们是不用管的,直接用就行了。
在上图的左上角,还可以看到一个default_random_engine的类。它也是一个实例化的类。之所以不归入那三种算法,是因为它的实现是由编译器厂家决定的,有的可能用linear_congruential_engine实现,有的可能用mersenne_twister_engine实现。这种现象在C/C++中见多了。不过,对于其他的类,C++11是有明确规定用哪种算法和参数实现的。
好了,说了这么多还是上一个例子吧。
- #include<iostream>
- #include<random>
- usingstd::cout;
- usingstd::endl;
- usingstd::cin;
- intmain()
- {
- std::default_random_engine random;
- for(int i = 0; i < 20; ++i)
- cout<<random()<<' ';
- cout<<endl;
- return 0;
- }
- //gcc编译器需要加上 –std=c++11 选项。
C++11中,随机数都是定义在random头文件中的。除了default_random_engine,其他的那些实例化随机数类的名字都是怪怪的,所以还是这个好用。从例子中可以看到,是通过operator ()函数来获取下一个随机数。
对srand熟悉的码农们肯定发现,这里没有使用到随机数种子。其实这里使用了默认种子,默认种子的值可以通过这类的公共静态常量default_seed来获取。如果想为这个类设置自己的种子的话,那么可以通过在构造函数中传入一个参数。也可以在构造之后调用seed()成员函数设置种子。
产生均匀分布的随机数:
上面例子产生的随机数会比较大,如果我们只想产生0到100的随机数。按照我们之前的做法是直接random()%100。这种做法是不好的。原因可以参见《Accelerated C++》的7.4.4节。
C++11也知道这一点,这就使得C++11的随机数更加复杂了。
我们平常说产生随机数,隐含是意思是产生均匀分布的随机数。学过概率论的同学都知道,除了均匀分布还有很多分布,比如正态分布、泊松分布等等。之前在网上看过网友怎么用rand()函数产生的随机数制作这些分布。现在这工作不用码农做了,C++11标准都提供了这些分布。
C++11提供的均匀分布模板类为:uniform_int_distribution和uniform_real_distribution。前一个模板类名字中的int不是代表整型,而是表示整数。因为它是一个模板类,可以用int、long、short等整数类型来实例化。后一个表示浮点数模板类,可以用float和double来实例化。使用例子如下:
- #include<iostream>
- #include<random>
- #include<time.h>
- using std::cout;
- using std::endl;
- using std::cin;
- int main()
- {
- std::default_random_engine random(time(NULL));
- std::uniform_int_distribution<int> dis1(0, 100);
- std::uniform_real_distribution<double> dis2(0.0, 1.0);
- for(int i = 0; i < 10; ++i)
- cout<<dis1(random)<<' ';
- cout<<endl;
- for(int i = 0; i < 10; ++i)
- cout<<dis2(random)<<' ';
- cout<<endl;
- return 0;
- }
可以看到,在uniform_int_distribution的构造函数中,参数说明了随机数的范围。uniform_int_distribution的随机数的范围不是半开范围[ ),而是[ ],对于uniform_real_distribution却是半开范围[ )。也是就是说上面的例子中,能产生100,但不会产生1.0。不得不说,这颠覆了之前的认识。对于default_random_engine来说,其产生的随机数范围是在[min(), max()]之间,其中min()和max()为它的两个成员函数。同样,也是非半开范围。对于浮点数,如果真的是想产生[0.0, 1.0]范围的数,可以使用
- #include<cmath>
- #include<cfloat>
- std::uniform_real_distribution<double> dis2(0, std::nextafter(1,DBL_MAX));
如果uniform_int_distribution使用了无参构造函数,那么其随机数的范围是[0,numberic_limits<type>::max()],也就是0到对应实例化类型能表示的最大值。对于uniform_real_distribution的无参构造函数,则是[0, 1)。
mt19937
当你第一眼看到这玩意儿的时候
肯定禁不住吐槽:纳尼?这是什么鬼?
确实,这个东西鲜为人知,但是它却有着卓越的性能
简介
mt19937是c++11中加入的新特性
它是一种随机数算法,用法与rand()函数类似
但是具有速度快,周期长的特点(它的名字便来自周期长度:2^19937-1)
说的直白一点,我们都知道rand()在windows下生成的数据范围为0-32767
但是这个函数的随机范围大概在(−maxint,+maxint)(−maxint,+maxint)(maxint为int类型最大值)
实例
这个东西用法非常简单
- #include<random>
- #include<ctime>
- std::mt19937 rnd(time(0));
- int main()
- {
- printf("%lld\n",rnd());
- return 0;
- }
概率分布类型:
C++11提供的概率分布类型有下面这些:
均匀分布:
uniform_int_distribution 整数均匀分布
uniform_real_distribution 浮点数均匀分布
伯努利类型分布:(仅有yes/no两种结果,概率一个p,一个1-p)
bernoulli_distribution 伯努利分布
binomial_distribution 二项分布
geometry_distribution 几何分布
negative_biomial_distribution 负二项分布
Rate-based distributions:
poisson_distribution 泊松分布
exponential_distribution指数分布
gamma_distribution 伽马分布
weibull_distribution 威布尔分布
extreme_value_distribution 极值分布
正态分布相关:
normal_distribution 正态分布
chi_squared_distribution卡方分布
cauchy_distribution 柯西分布
fisher_f_distribution 费歇尔F分布
student_t_distribution t分布
分段分布相关:
discrete_distribution离散分布
piecewise_constant_distribution分段常数分布
piecewise_linear_distribution分段线性分布
这些概率分布函数都是有参数的,在类的构造函数中把参数传进去即可。
下面是一个泊松分布的例子
- #include<iostream>
- #include<random>
- #include<time.h>
- #include<iomanip>
- intmain()
- {
- const int nrolls = 10000; // number ofexperiments
- const int nstars = 100; // maximum number of stars to distribute
- int parameter = 4;
- std::minstd_rand engine(time(NULL));
- std::poisson_distribution<int>distribution(parameter);
- int p[20]={};
- for (int i=0; i<nrolls; ++i)
- {
- int number = distribution(engine);
- if (number < 20)
- ++p[number];
- }
- std::cout << "poisson_distribution"<<parameter<< std::endl;
- for (int i=0; i < 20; ++i)
- std::cout<<std::setw(2)<< i<< ": " << std::string(p[i]*nstars/nrolls, '*') <<std::endl;
- return 0;
- }
某一个输出结果为:
可能大家都忘了泊松分布了,看一下下面的图吧
真正的随机数:
C++11还提供了一个random_device随机数类。它并不是由某一个数学算法得到的随机序列,而是通过读取文件,读什么文件看具体的实现(Linux可以通过读取/dev/random文件来获取)。文件的内容是随机的,因为文件内容是计算机系统的熵(熵指的是一个系统的混乱程度)。也是当前系统的环境噪声,系统噪音可以通过很多参数来评估,如内存的使用,文件的使用量,不同类型的进程数量等等。Linux的熵来自键盘计时、鼠标移动等。
不过gcc好像并没有很好地实现这个类,我手里的Mingw4.9.0就不随机,每次运行都得到同样的序列。
对于C++11的随机类的更多用法可以参考这里。
参考:《C++标准库 ——自学教程与参考手册》(第2版)
《C++ Primer》(第5版)
http://blog.csdn.net/akonlookie/article/details/8223525
http://stackoverflow.com/questions/19665818/best-way-to-generate-random-numbers-using-c11-random-library?rq=1
http://hipercomer.blog.51cto.com/4415661/857870
[转]C++11 随机数学习的更多相关文章
- 201521123082 《Java程序设计》第11周学习总结
201521123082 <Java程序设计>第11周学习总结 标签(空格分隔):java 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. Answe ...
- 201521123067 《Java程序设计》第11周学习总结
201521123067 <Java程序设计>第11周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 本次PTA作业题集多线 ...
- 201521123045 <java程序设计>第11周学习总结
201521123045 <java程序设计>第11周学习总结 1. 本周学习总结 2. 书面作业 2. 书面作业 Q1.1.互斥访问与同步访问完成题集4-4(互斥访问)与4-5(同步访问 ...
- 2018面向对象程序设计(Java)第11周学习指导及要求
2018面向对象程序设计(Java)第11周学习指导及要求 (2018.11.8-2018.11.11) 学习目标 (1) 掌握Vetor.Stack.Hashtable三个类的用途及常用API: ...
- 20172333 2017-2018-2 《Java程序设计》第11周学习总结
20172333 2017-2018-2 <Java程序设计>第11周学习总结 教材学习内容 对于Android Studio的安装以及对安卓的一些基本组成,比如说四大组件Acticity ...
- 20145202马超 2016-2017-2 《Java程序设计》第11周学习总结
20145202马超 2016-2017-2 <Java程序设计>第11周学习总结 教材学习内容总结 XX 教材学习中的问题和解决过程 教材学习有问题先去https://shimo.im/ ...
- C++11并发学习之三:线程同步(转载)
C++11并发学习之三:线程同步 1.<mutex> 头文件介绍 Mutex又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 <mutex> 头文 ...
- 面向对象程序设计(JAVA) 第11周学习指导及要求
2019面向对象程序设计(Java)第11周学习指导及要求 (2019.11.8-2018.11.11) 学习目标 理解泛型概念: 掌握泛型类的定义与使用: 掌握泛型方法的声明与使用: 掌握泛型接 ...
- 20175316盛茂淞 2018-2019-2 《Java程序设计》第11周学习总结
20175316 <Java程序设计> 第11周学习总结 教材内容学习总结 第十三章 URL类 URL类是java.net包中的一个重要的类,URL的实例封装着一个统一资源定位符,使用UR ...
随机推荐
- BugPhobia准备篇章:团队Beta阶段准备工作分析
0x00:序言 To the searching tags, you may well fall in love withhttp://xueba.nlsde.buaa.edu.cn/ 再见,无忧时光 ...
- 图文转化(Alpha)版使用说明
图文转化使用说明 本软件是一款扫描图片上的文字转化成txt或doc格式存储的软件. 现在还只是初期简单的一个实现,软件暂时的界面显示如下: 简介:照片选取的是手机里的本地照片,拍照打开照相机进行拍照. ...
- 第二阶段Sprint7
昨天:将“录制”及“保存”整合到一起,修复出现的Bug,使之能够正常运行. 今天:把视频录制整合到时间提醒里,实现视频提醒 遇到的问题:额,整进去直接就停止运行了..也没有报错..
- 基于Winform框架DataGridView控件的SqlServer数据库查询展示功能的实现
关键词:Winform.DataGridView.SqlServer 一个基于winform框架的C/S软件,主要实现对SqlServer数据库数据表的实时查询. 一.为DataGridView添加数 ...
- jdk命令行工具:jstat与jmap
转自文章:http://blog.csdn.net/gzh0222/article/details/8538727 C:\Users\Administrator\Desktop>jstat -g ...
- [转帖]你们知道LTE Cat.1到Cat.10 那Cat.0呢?
你们知道LTE Cat.1到Cat.10 那Cat.0呢? https://network.pconline.com.cn/638/6389637_all.html#content_page_3 1大 ...
- 微信小程序初窥-环境搭建
关于微信小程序的背景知识,在此不做阐述,可以自行搜索了解.本文将介绍微信小程序的账号的注册,IDE的下载,创建一个实例小程序. 1.注册小程序 前去链接:https://mp.weixin.qq.co ...
- PowerExchange实时抽取架构介绍
工作原理 准实时抽取架构图: 以上共有核心业务系统数据库服务器.ETL服务器.BI数据库服务器[目标数据库服务器],三台服务器和ETL客户端(PowerCenter客户端).其中核心业务系统上有核心系 ...
- springMVC的接受参数三种样例
- python接口自动化感悟
一个方法对应一个接口,每个方法都要有登陆 成一个独立的逻辑功能块