标签:
本文主要参考自一博文及cplusplus和cppreferrence。其中,该博文是对cplusplus上该伪随机数条目的翻译,下文中会参考调整。
C++中伪随机数库Random是C++11才开始添加的。它允许我们结合生成器(Generators)和分布器(Distributions)来生成伪随机数。
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 }
如果我们嫌每次都要传入生成器对象麻烦,我们可以使用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 }
其实我们会发现上边两个代码的结果不管跑多少次都是一样的,很奇怪!我们可以试着给生成器一个种子,如下:
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 }
现在我们看到结果不一样了。但是,不管我们再跑多少次,其结果还是一样的,这就更加奇怪了。究其原因,在于我们设定的种子是固定的。对于计算机而言,当输入确定时,输出也一定是确定的。因为生成器算法和分布器算法都是确定的,所以当输入是确定的时候,输出也必然是确定的。因此,为了得到不一样的结果,我们可以将系统时间当作种子:
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 }
关于生成器和分布器,请参照cplusplus手册。
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 }
我们可以发现上述例子用到了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 }
可能的输出是:
1 default random_device characteristics: 2 minimum: 0 3 maximum: 4294967295 4 entropy: 32 5 a random number: 4230014324
有些情况下,随了拿时间当种子,random_device也经常被用来生成种子。
标签:
原文地址:http://www.cnblogs.com/xiehongfeng100/p/4355442.html