随机算法在程序设计里的使用频度就不用我说了。一般我们用到的随机算法 都是伪随机算法,什么叫伪随机算法呢?伪随机算法意思是假如知道第一个随机种子和随机算法的话就可以推算出下一个随机数。通常我们程序里都是通过当前时间 作为随机函数的第一个随机种子,然后将随机函数返回的值作为下一个种子,随机函数是一个公用函数,每个用户的请求都会触发一个新的随机种子,所以说是随机 的。很多公司都有自己的一套随机算法,下面看一下一位前辈的总结。
/********************************************************************
参考:http://www.cppblog.com/Chipset/archive/2009/02/07/73177.html
我们讲的随机数其实暗指伪随机数。提及随机数,不少朋友可能想到C语言的库函数rand(),rand()随机性太差,速度太慢。
古老的LCG(linear congruential generator)代表了最好的伪随机数产生器算法。主要原因是容易理解,容易实现,而且速度快。
这种算法数学上基于X(n+1) = (a * X(n) + c) % m这样的公式,其中:
模m, m > 0
系数a, 0 < a < m
增量c, 0 <= c < m
原始值(种子) 0 <= X(0) < m
其中参数c, m, a比较敏感,或者说直接影响了伪随机数产生的质量。
一般而言,高LCG的m是2的指数次幂(一般2^32或者2^64),因为这样取模操作截断最右的32或64位就可以了。
多数编译器的库中使用了该理论实现其伪随机数发生器rand()。下面是部分编译器使用的各个参数值:
Source m a c rand() / Random(L)的种子位
Numerical Recipes
2^32 1664525 1013904223
Borland C/C++
2^32 22695477 1 位30..16 in rand(), 30..0 in lrand()
glibc (used by GCC)
2^32 1103515245 12345 位30..0
ANSI C: Watcom, Digital Mars, CodeWarrior, IBM VisualAge C/C++
2^32 1103515245 12345 位30..16
Borland Delphi, Virtual Pascal
2^32 134775813 1 位63..32 of (seed * L)
Microsoft Visual/Quick C/C++
2^32 214013 2531011 位30..16
Apple CarbonLib
2^31-1 16807 0 见Park–Miller随机数发生器
*********************************************************************/
再来看看linux内核提供的一个随机算法,linux下的随机数是通过你上次操作外围设备和这次的时间差产生的随机数。其实区别就在于随机种子的产 生。linux下将随机种子作为bytes流输出到/dev/random这个文件里,我们可以访问,并运用。下面我就通过linux提供的这个接口写个 dota下非常常用的命令,roll。相信玩dota的玩家都很熟悉吧,好的废话不多说,来看咱的roll随机程序。
- #include <stdio.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <assert.h>
- /* return a random integer between Min and Max. inclusive. obtain
- randomness from /dev/random */
- int random_number(int min, int max)
- {
- /* store a file descriptor opened to /dev/random in a static variable
- ,that way ,we don't need to open the file every time this function is called. */
- static int dev_random_fd = -1;
- char* next_random_byte;
- int byte_to_read;
- unsigned random_value;
- /* make sure max is greater then min */
- assert(max > min);
- /* if this is frist time the function is called, open a file descriptor to /dev/random. */
- if(dev_random_fd == -1){
- dev_random_fd = open("/dev/random", O_RDONLY);
- assert(dev_random_fd != -1);
- }
- /* read enough bytes to fill an integer variable.*/
- next_random_byte = (char*)&random_value;
- byte_to_read = sizeof(random_value);
- /* loop until we'v readed enough bytes. Because /dev/random is filled from user genered action.
- the read may block or only return a single random byte at a time.*/
- do{
- int bytes_read;
- bytes_read = read(dev_random_fd, next_random_byte, byte_to_read);
- byte_to_read -= bytes_read;
- next_random_byte += bytes_read;
- }while(byte_to_read > 0);
- /* compute a random number in the correct range */
- return min + (random_value % (max - min + 1));
- }
- int main(int argc, char* argv[])
- {
- /* int min = argv[1]; */
- int min;
- int max;
- if(argv[1] == 0x0)
- {
- max = 100;
- min = 0;
- }
- else if(argv[1] != NULL && argv[2] == NULL)
- {
- min = 0;
- max = atoi(argv[1]);
- }
- else
- {
- max = atoi(argv[2]);
- min = atoi(argv[1]);
- }
- int random_num = random_number(min, max);
- printf("You have tossed:%d/ttop limit is:%d/n", random_num, max);
- return 0;
- }
我是在ubuntu9.04下gcc编译通过的,有兴趣的同学可以试试。