码迷,mamicode.com
首页 > 编程语言 > 详细

C/C++中如何产生伪随机数

时间:2015-03-21 13:54:54      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:

  本文主要参考自一博文cpluspluscppreferrence。其中,该博文是对cplusplus上该伪随机数条目的翻译,下文中会参考调整。

  1. C语言中的伪随机数产生函数

 

  2. C++语言中的伪随机数产生器

  C++中伪随机数库Random是C++11才开始添加的。它允许我们结合生成器(Generators)和分布器(Distributions)来生成伪随机数。 

  生成器(Generators):能够产生离散的等可能分布数值。
  分布器(Distributions): 能够把生成器产生的均匀分布值映射到其他各种各样的分布,如均匀分布uniform,正态分布normal,二项分布binomial,泊松分布poisson。

   2.1 一个简单的例子

  下边就是一个简单的例子:
技术分享
 1 #include <iostream>
 2 #include <random>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     default_random_engine generator;
 8     uniform_int_distribution<int> dis(0, 6);
 9     for (int i = 0; i < 6; i++)
10     {
11         std::cout << dis(generator) << std::endl;    // 1 0 1 1 2 6
12     }
13 
14     return 0;
15 }
View Code

  如果我们嫌每次都要传入生成器对象麻烦,我们可以使用std::bind来绑定生成器对象和分布器对象(注意bind在头文件functional中)。如下所示:

技术分享
 1 #include <iostream>
 2 #include <random>
 3 #include <functional>    // std::bind
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     default_random_engine generator;
 9     uniform_int_distribution<int> dis(0, 6);
10     auto dice = bind(dis, generator);
11     for (int i = 0; i < 6; i++)
12     {
13         std::cout << dice() << std::endl;    // 1 0 1 1 2 6
14     }
15 
16     return 0;
17 }
View Code

  其实我们会发现上边两个代码的结果不管跑多少次都是一样的,很奇怪!我们可以试着给生成器一个种子,如下:

技术分享
 1 #include <iostream>
 2 #include <random>
 3 #include <functional>    // std::bind
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     default_random_engine generator(10);    // seed = 10
 9     uniform_int_distribution<int> dis(0, 6);
10     auto dice = bind(dis, generator);
11     for (int i = 0; i < 6; i++)
12     {
13         std::cout << dice() << std::endl;    // 2 0 4 1 2 4
14     }
15 
16     return 0;
17 }
View Code

  现在我们看到结果不一样了。但是,不管我们再跑多少次,其结果还是一样的,这就更加奇怪了。究其原因,在于我们设定的种子是固定的。对于计算机而言,当输入确定时,输出也一定是确定的。因为生成器算法和分布器算法都是确定的,所以当输入是确定的时候,输出也必然是确定的。因此,为了得到不一样的结果,我们可以将系统时间当作种子:

技术分享
 1 #include <iostream>
 2 #include <random>
 3 #include <functional>    // std::bind
 4 #include "time.h"        // time
 5 using namespace std;
 6 
 7 int main()
 8 {
 9     default_random_engine generator(time(NULL));
10     uniform_int_distribution<int> dis(0, 6);
11     auto dice = bind(dis, generator);
12     for (int i = 0; i < 6; i++)
13     {
14         std::cout << dice() << std::endl;
15     }
16 
17     return 0;
18 }
View Code

   2.2 关于生成器和分布器

  关于生成器和分布器,请参照cplusplus手册。

  下边是一个来自cppreferrence的例子:
技术分享
 1 #include <iostream>
 2 #include <iomanip>
 3 #include <string>
 4 #include <map>
 5 #include <random>
 6 #include <cmath>
 7 using namespace std;
 8 
 9 int main()
10 {
11     // Seed with a real random value, if available
12     std::random_device rd;
13     cout << rd() << endl;
14     // Choose a random mean between 1 and 6
15     std::default_random_engine e1(rd());
16     std::uniform_int_distribution<int> uniform_dist(1, 6);
17     int mean = uniform_dist(e1);
18     std::cout << "Randomly-chosen mean: " << mean << \n;
19 
20     // Generate a normal distribution around that mean
21     std::mt19937 e2(rd());
22     std::normal_distribution<> normal_dist(mean, 2);    // default: double
23 
24     std::map<int, int> hist;
25     for (int n = 0; n < 10000; ++n) {
26         ++hist[std::round(normal_dist(e2))];
27     }
28     std::cout << "Normal distribution around " << mean << ":\n";
29     for (auto p : hist) {
30         std::cout << std::fixed << std::setprecision(1) << std::setw(2)
31             << p.first <<   << std::string(p.second / 200, *) << \n;
32     }
33 
34     return 0;
35 }
View Code

  我们可以发现上述例子用到了random_device这个生成器。该生成器产生的是非确定性随机数。在Linux的实现中,是读取/dev/urandom设备;在Windows的实现居然是用rand_s。random_device提供()操作符,用来返回一个min()到max()之间的一个数字(min()、max()均为该生成器成员函数)。如果是Linux(Unix Like或者Unix)下,都可以使用这个来产生高质量的随机数,可以理解为真随机数。

  一个例子如下:
技术分享
 1 // random_device example
 2 #include <iostream>
 3 #include <random>
 4 
 5 int main ()
 6 {
 7   std::random_device rd;
 8 
 9   std::cout << "default random_device characteristics:" << std::endl;
10   std::cout << "minimum: " << rd.min() << std::endl;
11   std::cout << "maximum: " << rd.max() << std::endl;
12   std::cout << "entropy: " << rd.entropy() << std::endl;
13   std::cout << "a random number: " << rd() << std::endl;
14 
15   return 0;
16 }
View Code

  可能的输出是:

技术分享
1 default random_device characteristics:
2 minimum: 0
3 maximum: 4294967295
4 entropy: 32
5 a random number: 4230014324
View Code

  有些情况下,随了拿时间当种子,random_device也经常被用来生成种子。

 

C/C++中如何产生伪随机数

标签:

原文地址:http://www.cnblogs.com/xiehongfeng100/p/4355442.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!