很多人在用c语言产生随机数时多半会使用链接里给出的方法。这种方法有种缺点,比如,rand()的范围是[0, 15),那么,rand() % 10时,9的概率就会小于5。c++11里面提供了一种解决方案,本文对这个解决方案做一个简略地介绍。
这个例子可以当成一个模板直接套用,不过更好的方法还是自己封装一下常用的方法。
// 代码来源于 The C++ Standard Library - 2nd Edition #include <random> #include <iostream> #include <algorithm> #include <vector> int main() { // create default engine as source of randomness std::default_random_engine dre; // use engine to generate integral numbers between 10 and 20 (both included) // 常用 std::uniform_int_distribution<int> di(10,20); for (int i=0; i<20; ++i) { std::cout << di(dre) << " "; } std::cout << std::endl; // use engine to generate floating-point numbers between 10.0 and 20.0 // (10.0 included, 20.0 not included) // 常用 std::uniform_real_distribution<double> dr(10,20); for (int i=0; i<8; ++i) { std::cout << dr(dre) << " "; } std::cout << std::endl; // use engine to shuffle elements // 打乱数组 std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; std::shuffle (v.begin(), v.end(), // range dre); // source of randomness for (int i=0; i<v.size(); ++i) { std::cout << v[i] << " "; } std::cout << std::endl; }要产生随机数,需要两个部分,一是engine,二是distribution。engine是一种描述随机性状态的函数对象,通过特定的算法产生一系列均匀、预定义的无符号伪随机数,所以,基本上相同类engine的不同对象在不同平台(default_random_engine在不同的平台上产生的随机数列可能不一样)上会产生一系列相同的随机数列;distribution就是概率论里的分布,通过传入的engine产生符合分布的随机数,一般使用均匀分布。
engine可以简单看成一个无限数列{a0, a1, a2, …},当中的每个值都是一个状态,由于engine本身是函数对象,每调用一次就会产生一个无符号随机数,例如ai,并且改变当前状态到ai+1。因此,一般来说,如果不提前设置状态,默认都是从a0 开始,在同一台电脑上,不同的engine会产生相同的数。为了方便,一般使用default_random_engine:
std::default_random_engine dre;如果想要每次产生的无符号随机数不同,则可以考虑时间作为初始状态:
std::default_random_engine dre(选一个初始状态);或是使用seed()成员函数改变状态,更多用法这里。
这个是根据传入的engine产生符合分布的随机数,可以是均匀分布,二项分布,正态分布等等。它会调用传入的engine对象,并且使engine的状态改变。最常用的均匀分布在例子里已经给出,更多细节见这里。
关于均匀分布用法的一个例子 // [来源](http://www.cplusplus.com/reference/random/uniform_int_distribution/uniform_int_distribution/uniform_int_distribution example) #include <iostream> #include <chrono> #include <random> int main() { // construct a trivial random generator engine from a time-based seed: unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator (seed); std::uniform_int_distribution<int> distribution(1,100); int guess; int number = distribution(generator); while (true) { std::cout << "guess the number (between 1 and 100): "; std::cin >> guess; if (number==guess) {std::cout << "right!\n"; break; } else if (number>guess) std::cout << "it's greater\n"; else std::cout << "it's less\n"; } return 0; }