C++随机数实例
来源:互联网 发布:仙人指路源码选股公式 编辑:程序博客网 时间:2024/06/01 10:19
转自: http://blog.csdn.net/songshimvp1/article/details/47016805
旧式的随机数发生器沿用C的Rand()函数,这个函数会产生区间在[0,RAND_MAX]的伪随机数,且随机数近似可以看做符合均匀分布。
传统做法的弊端大致有两个:
1、经常需要做人肉变换随机数产生区间,且人肉变换过程中极易破坏原有的分布性质;
2、难以产生符合制定分布的随机数;
rand()函数的一些问题:
很多程序需要不同范围的随机数;
一些应用需要随机浮点数;
一些程序需要非均匀分布的数;
而程序员为了解决这些问题而试图转换rand生成的随机数的范围、类型或分布时,常常会引入非随机性。
一、C++ 11新标准针对这两点做了很大的改进——随机数发生器(定义在头文件random)。
新设施利用两部分来生成随机数:
(1)、random number engines(引擎类):负责生成原始随机数
(2)、random number distributions(分布类): 迫使生成的随机数在统计上满足指定的概率分布
STL预先指定了一系列的生成引擎,并且提供一个default_random_engine。default_random_engine会使用某个预定义的引擎,且不同编译器、不同平台的实现可能不同。
PS:有关详细的预定义引擎及分布类列表:
例子1:
- std::default_random_engine e;
- for (size_t i = 0; i < 10; i++) {
- cout << e() << endl;
- }
例子2:
可以指定随机数要符合的分布性质,例如说,在[5,20]上的均匀分布。
- std::default_random_engine e;
- std::uniform_int_distribution<> u(5,20);
- for (size_t i = 0; i < 10; i++) {
- cout << u(e) << endl; //注意!
- }
注意:我们传递给分布对象的是引擎对象本身,即u(e)。我们传递的是引擎本身,而不是它生成的下一个值,原因是某些分布可能需要调用引擎多次才能产生一个值。如果我们将调用写成u(e()),含义就变为将e生成的下一个值传递给u,这将会导致一个编译错误。
- //int rand_num = rand()%11;//rand获取0-10随机数的方法
- //default_random_engine也同样可以指定随机数范围,那就是它的好基友分布类型:uniform_int_distribution
- uniform_int_distribution<unsigned> u(0,10);//生成0到10(包含)均匀分布的随机数
- default_random_engine e;//生成随机无符号数
- for(int i=0;i<10;++i)
- {
- cout << u(e) << endl;//u的范围范围便是e生成的随机数范围
- }
例子3:
关于种子。
- std::default_random_engine e(time(nullptr));
- std::uniform_int_distribution<> u(5,20);
- }
不过,由于time的精度是秒,所以在某些极端情况下,这也并不是一个非常好的选择。另外,如果程序作为一个自动过程的一部分反复运行,将time的返回值作为种子的方式就无效了,它可能多次使用的相同的种子。
幸运的,C++11提供了一个非常友好的类:random_device。这个类的作用是,可以产生non-deterministic random numbers.
这个类有可能产生真正的随机数,不过真是效果和具体实现有关。某些平台可能才用伪随机数作为底层实现也说不定呢…
显然的,我们可以利用random_device去初始化我们的随机数种子
- std::random_device rd;
- std::default_random_engine e(rd());
- std::uniform_int_distribution<> u(5,20);
- for (size_t i = 0; i < 10; i++) {
- cout << u(e) << endl;
- }
例子4:
为引擎设置种子的方式有两种,一种是创建时初始化种子,另一种是调用seed来初始化。
- default_random_engine e1; //使用默认的种子
- default_random_engine e2(2300); //使用给定的种子
- default_random_engine e3;
- e3.seed(2300); //e3使用的种子与e2是一样一样的。
三、生成随机浮点数。
程序需要0到1之间的随机数。
最常用但是不正确的做法:从rand获得一个随机浮点数的方法是用rand()的结果除以RADN_MAX——即系统定义的rand可以生成的最大随机数的上界。——这种方法不正确的原因是:随机整数的精度通常低于随机浮点数,这样,有一些浮点数就永远不会生成了!
使用c++11的随机数发生器,可以让标准库来处理从随机整数到随机浮点数的映射。
- void main()
- {
- default_random_engine e; //生成无符号的随机整数
- uniform_real_distribution<double> u(0, 1); //0到1(包含)的均匀分布
- for (size_t i = 0; i < 10; ++i)
- {
- cout << u(e) << " "; //<span style="font-size: 18px;">从随机整数到随机浮点数的映射</span>
- }
- }
四、生成非均匀分布的随机数
比如伯努利分布、正态分布、抽样分布、泊松分布等。例子:生成一个正态分布的值序列,并画出值的分布。
- int main()
- {
- default_random_engine e; // generates random integers
- normal_distribution<> n(4,1.5); // 4为中心,标准差为1.5
- vector<unsigned> vals(9); // nine elements each 0
- for (size_t i = 0; i != 200; ++i)
- {
- unsigned v = lround(n(e)); // normal_distribution<>生成的是浮点值,使用头文件ctime中的lround函数将每个随机数舍入到最接近的整数
- if (v < vals.size()) // if this result is in range
- ++vals[v]; // count how often each number appears
- }
- int sum = accumulate(vals.begin(), vals.end(), 0);
- if (sum != 200)
- cout << "discarded " << 200 - sum << " results" << endl;
- for (size_t j = 0; j != vals.size(); ++j)
- cout << j << ": " << string(vals[j], '*') << endl;//打印一个由*组成的string
- return 0;
- }
特别注意:一个给定的随机数发生器一直会产生相同的随机数序列。一个函数如果定义了局部的随机数发生器,应该将其(引擎对象+分布对象)定义为static的。否则,每次调用函数都会生成相同的序列。
- #include<iostream>
- #include<vector>
- #include<random>
- using namespace std;
- /*vector<unsigned> bad_rand()
- {
- default_random_engine e;//随机数引擎类型之一,在大多数情况下(通常情况下)获得好的性能
- uniform_int_distribution<unsigned> u(0, 9); //随机数分布类型之一
- vector<unsigned> vec;
- for (size_t i = 0; i < 10; i++)
- {
- vec.push_back(u(e));
- }
- return vec;
- }
- void main()
- {
- vector<unsigned> v1(bad_rand());
- for (size_t k = 0; k < 10; k++)
- {
- cout << "v1:" << v1[k] << endl;
- }
- vector<unsigned> v2(bad_rand());
- for (size_t k = 0; k < 10; k++)
- {
- cout << "v2:" << v2[k] << endl;
- }
- cout << ((v1 == v2) ? "equal" : "not equal" )<< endl;//打印“equal”!
- //v1 : 2
- //v1 : 2
- //v1 : 4
- //v1 : 5
- //v1 : 4
- //v1 : 1
- //v1 : 9
- //v1 : 5
- //v1 : 8
- //v1 : 3
- //v2 : 2
- //v2 : 2
- //v2 : 4
- //v2 : 5
- //v2 : 4
- //v2 : 1
- //v2 : 9
- //v2 : 5
- //v2 : 8
- //v2 : 3
- //equal
- //随机数发生器此特性会使新手迷惑:即使生成的书看起来是随机的,但对一个给定的发生器,每次运行程序它都会返回相同的数值序列。
- //<strong>序列不变这一事实</strong>在调试时非常有用。但是另外一方面,使用随机数发生器的程序也必须注意这一点。
- }*/
- //<span style="color:#ff0000;">解决上述问题的办法:</span>
- vector<unsigned> good_rand()
- {
- //<strong>解决这一问题的办法是</strong>:将引擎和关联的分布对象定义为“static”的。
- //将它们定义为“static”,因此它们在函数调用之间会保持住状态,从而每次调用都产生新的数据。
- static default_random_engine e;
- static uniform_int_distribution<unsigned> u(0, 9);
- vector<unsigned> vec;
- for (size_t i = 0; i < 10; i++)
- {
- vec.push_back(u(e));
- }
- return vec;
- }
- void main()
- {
- vector<unsigned> v1(good_rand());
- for (size_t k = 0; k < 10; k++)
- {
- cout << "v1:" << v1[k] << endl;
- }
- vector<unsigned> v2(good_rand());
- for (size_t k = 0; k < 10; k++)
- {
- cout << "v2:" << v2[k] << endl;
- }
- cout << ((v1 == v2) ? "equal" : "not equal") << endl;//打印“not equal”!
- //v1 : 2
- //v1 : 2
- //v1 : 4
- //v1 : 5
- //v1 : 4
- //v1 : 1
- //v1 : 9
- //v1 : 5
- //v1 : 8
- //v1 : 3
- //v2 : 5
- //v2 : 5
- //v2 : 0
- //v2 : 6
- //v2 : 9
- //v2 : 0
- //v2 : 9
- //v2 : 4
- //v2 : 7
- //v2 : 6
- //not equal
- }
- C#--实例选号器生成随机数
- 【Unity&C#&随机数】随机数
- 【C++】随机数
- java随机数实例
- shell实例(九) ---随机数
- shell编程随机数实例
- python实例:产生随机数
- Java 实例-产生随机数
- C++随机数实例
- 一起talk C栗子吧(第六回:C语言实例--生成随机数)
- c++/c 产生随机数
- C/C++:随机数生成
- C/C++产生指定范围和不定范围随机数的实例代码
- obj-c编程15[Cocoa实例01]:一个会发声的随机数生成器
- [C]如何产生随机数~
- C 语言中的随机数
- C#.net随机数函数
- C语言随机数内幕
- Python杂记
- 百度语音合成案例分享
- 从直播CDN原理说起
- 推荐几款Android好用的插件
- Python初学之抽象类
- C++随机数实例
- CC2640R2F BLE5.0 蓝牙协议栈OAD功能问题集锦
- 堪称最好的A*算法
- [Leetcode] 335. Self Crossing 解题报告
- C#:string、stringBuffer、stringBuilder的区别
- bzoj 3166 可持久化Tire
- 215. Kth Largest Element in an Array
- 分享Kali Linux 2017年第31周镜像文件
- Linux内核中的常用宏container_of其实很简单