随机数是人们生活中的必需品,比如说喝酒时的划拳,骰子,国人喜欢的斗地主,麻将,福彩,游戏中那就跟不用说了。所以说随机数的设计是关乎公平性最重要的决定因素。如果说前面提到的事件都可以预测的话,我想没有人会去参与这些事件。
模m, m > 0
系数a, 0 < a < m
增量c, 0 <= c < m
原始值(种子) 0 <= X(0) < m
其中参数c, m, a比较敏感,或者说直接影响了伪随机数产生的质量。
每个厂商对应都有自己的参数,如果对其它厂商的参数比较感兴趣的话可以 看这里 。随机算法都是通用的,程序中遇到不同的问题,需要根据情况来决定提供什么样的随机种子。通过上面的公式我们知道如果提供相同的种子每次产生的随机序列是一样的。所以程序中常用的方法是用当前时间来做随机算法的种子。但是通过当前时间就一定能每次产生的随机数是不一样的吗?
#include <iostream> #include <ctime> int GetRandNum(int min, int max) { srand(time(NULL)); return (min + rand() %(max - min +1)); } int main() { std::cout<<"the num is:"; for(int i = 0; i < 10; ++i) { std::cout<<GetRandNum(0, 10)<<"\t"; } std::cout<<"\n"; }
为什么结果都是一样的呢,这就是前面说的种子一样的话每次产生的随机数是一样的,因为time(NULL) 只能精确到秒,所以在一秒内程序很轻松执行完。遇到这种问题如何解决呢,当然用精度更高的纳秒是一种解决办法,也可以用当前的随机数做为下次随机的种子也是一种好的方式。
boost库自己提供的随机数发生器:
#include <boost/random/mersenne_twister.hpp> #include <boost/random/uniform_int_distribution.hpp> int main() { boost::random::mt19937 rng; boost::random::uniform_int_distribution<int> index_dis(0, 10); std::cout<<"the num is:"; for(int i =0; i < 10; ++i) { std::cout<<index_dis(rng)<<"\t"; } std::cout<<"\n"; return 0;
}
#include <iostream> #include <ctime> static int seed = time(NULL); int GetRandNum(int min, int max) { srand(seed); seed = rand(); return (min + rand() %(max - min +1)); } int main() { std::cout<<"the num is:"; for(int i = 0; i < 10; ++i) { std::cout<<GetRandNum(1, 10)<<"\t"; } std::cout<<"\n"; }
facebook的随机种子:
#include "folly/Random.h" #include <unistd.h> #include <sys/time.h> namespace folly { uint32_t randomNumberSeed() { struct timeval tv; gettimeofday(&tv, NULL); const uint32_t kPrime1 = 61631; const uint32_t kPrime2 = 64997; const uint32_t kPrime3 = 111857; return kPrime1 * static_cast<uint32_t>(getpid()) + kPrime2 * static_cast<uint32_t>(tv.tv_sec) + kPrime3 * static_cast<uint32_t>(tv.tv_usec); } }
boost的随机发生器
#include <boost/random/mersenne_twister.hpp> #include <boost/random/discrete_distribution.hpp> #include <iostream> #include <map> #include <ctime> #include <sys/time.h> #define TEST_COUNT 10000000 int main() { boost::mt19937 gen; double probabilities[] ={0.1, 0.12, 0.2, 0.26, 0.32}; boost::random::discrete_distribution<> dist(probabilities); struct timeval tim; gettimeofday(&tim, NULL); std::cout<<"start time:"<<tim.tv_sec<<"the micro sec is:"<<tim.tv_usec<<"\n"; std::map<float, int> statis_map; for(int i = 0; i < TEST_COUNT; ++i) { statis_map[probabilities[dist(gen)]]++; } gettimeofday(&tim, NULL); std::cout<<"end time:"<<tim.tv_sec<<"the micro sec is:"<<tim.tv_usec<<"\n"; for(std::map<float, int>::iterator iter = statis_map.begin(); iter != statis_map.end(); ++iter) { std::cout<<"the per:"<<iter->first<<"\tresult per:"<<(float)iter->second/TEST_COUNT<<"\n"; } return 0; }
结果为:
自制随机发生器
#include <iostream> #include <cmath> #include <ctime> #include <map> #include <sys/time.h> using namespace std; #define TEST_COUNT 10000000 static int s_rand = time(NULL); float RandomFloat() { srand(s_rand); int i = rand(); s_rand = i; return (float)(i%100)/100; } int main() { float per_array[] ={0.1, 0.12, 0.2, 0.26, 0.32}; timeval tim; gettimeofday(&tim, NULL); cout<<"start time:"<<tim.tv_sec<<"the micro sec is:"<<tim.tv_usec<<"\n"; map<float, int> per_map; for(int i = 0; i < TEST_COUNT; ++i) { float frand = RandomFloat(); float min = 0; float max = 1.0f; for(int i =0; i < 5; ++i){ min = max - per_array[i]; if(frand >= min){ per_map[per_array[i]]++; break; } max = min; } } gettimeofday(&tim, NULL); cout<<"end time:"<<tim.tv_sec<<"the micro sec is:"<<tim.tv_usec<<"\n"; map<float, int>::iterator iter = per_map.begin(); for(;iter != per_map.end(); ++iter) { float per_count = (float)iter->second; cout<<"the per:"<<iter->first<<"\tresult per:"<<per_count/TEST_COUNT<<endl; } return 0; }
结果为:
通过分析得知,两个随机发生器的概率分布,基本上和给出的概率非常吻合,运算速度的话,自制的随机发生器比boost几乎快一倍。经常听到很多人不要重新制造轮子,吐槽c++的程序员喜欢自造轮子。确实已经存在的东西没必要再去重写一边,因为那是浪费时间。但是并不代表说不会造轮子,假如都不知道如何造,又如何分辨轮子的好坏,哪些程序岂不要考蒙来写。那写出来的代码质量也是按随机概率分布的。。。。。
#include <boost/random/mersenne_twister.hpp> #include <boost/random/uniform_int_distribution.hpp> int main() { std::string chars( "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "1234567890" "!@#$%^&*()" "`~-_=+[{]{\\|;:'\",<.>/? "); boost::random::mt19937 rng; boost::random::uniform_int_distribution<int> index_dist(0, chars.size() - 1); std::cout<<"You pwd is:\t"; for(int i = 0; i < 8; ++i) { std::cout << chars[index_dist(rng)]; } std::cout << std::endl; }
结果:
自制随机发生器生成密码
#include <iostream> #include <string> #include <ctime> using namespace std; static int seed = time(NULL); int RandomRange(int min, int max) { srand(seed); seed = rand(); return (min + (rand())%(max-min)); } char RollChar() { std::string chars( "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "1234567890" "!@#$%^&*()" "`~-_=+[{]{\\|;:'\",<.>/? "); char ch = chars[RandomRange(0, chars.size())]; return ch; } string RollString(int min, int max) { int str_len = RandomRange(min, max); string str(str_len, '0'); for(int i = 0; i < str_len; ++i) { str[i] = RollChar(); } return str; } int main() { int count, min_length, max_length; cout<<"the count you want to:\n"; cin>>count; cout<<"the min, and max username length:\n"; cin>>min_length>>max_length; if(min_length > max_length || min_length < 0) { cout<<"you stupid boy!!!\n"; return 1; } for(int i = 0; i < count; ++i) { cout<<"the user name is:\t"<<RollString(min_length, max_length)<<"\tThe pwd:\t"<<RollString(8,10)<<endl; } return 0; }
结果:
可以根据这个算法写个生成账号密码的软件,专门来管理自己日常的密码,可以生成变态的用户名密码。
引用参考:
http://www.boost.org/doc/libs/1_50_0/doc/html/boost_random.html
http://en.wikipedia.org/wiki/Random_number_generation
http://blog.csdn.net/hackmind/article/details/6388044