Random Number Generation

原文链接如下:

http://www.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf

我只是进行了简单的翻译,目的是进一步了解KISS算法。

平时,当code中需要随机数的时候,我们往往求助于系统的函数,例如c语言的rand()函数。事实上,这些函数本省存在缺陷,它们不能够提供很好的随机数。当然在code中,不可能提供完全随机的数字,最好的状态只能是伪随机的数字。如果code中需要随机数的时候,我需要注意一下几点:

1.  不要采用系统提供的函数

2.  采用好的RNG算法,并且把它实现到你的code中。

3.  恰当地给RNG提供种子(seed)。

 

一.  不要采用系统提供的函数

以下给出的函数均有缺陷:

       Perl –- rand

       Python – random

       Java.Util.Random

       C – rand, random

       Matlab -- rand

二.  采用好的RNG算法,并且把它实现到你的code中

从软件的角度来看,它不可能实现完全随机的数字。因为这些数字是由算法产生的,而算法的定义是非随机。例如C语言经典的rand函数会交替的产生奇数和偶数,这本省就不是随机。可以参看这个链接。http://www.iro.umontreal.ca/~lecuyer/myftp/papers/testu01.pdf

一个好的RNG算法能通过如下的test case。http://www.phy.duke.edu/~rgb/General/dieharder.php

目前来看,KISS (keep it simple and stupid)算法能够通过上述的测试。

算法的基本表述如下:

static unsigned int x = 123456789,y = 362436000,z = 521288629,c = 7654321; 

/* Seed variables */ 

unsigned int KISS() {  

   unsigned long long t, a = 698769069ULL; 

   x = 69069*x+12345; 

   y ^= (y<<13); y ^= (y>>17); y ^= (y<<5); /* y must never be set to zero! */ 

   t = a*z+c; c = (t>>32); /* Also avoid setting z=c=0! */ 

   return x+y+(z=t); 

}

这个短小精悍的算法组合了3个不同的随机数发生器,其周期大约是10^37。该算法的种子x,y和z需要设置成大的数值。需要注意的是,上述的code采用的数据类型必须是unsigned long long。

基于上述算法。许多类似KISS的算法被提出来了,我提出的KISS算法如下:

/* Public domain code for JKISS RNG */ 

static unsigned int x = 123456789,y = 987654321,z = 43219876,c = 6543217; 

/* Seed variables */ 

unsigned int JKISS() 

{  unsigned long long t; 

   x = 314527869 * x + 1234567; 

   y ^= y << 5; y ^= y >> 7; y ^= y << 22; 

   t = 4294584393ULL * z + c; c = t >> 32; z = t; 

   return x + y + z; 

}


算法改进之处,包含了三个发生器。

当然,对于32位整数,也有对应的算法,Marsaglia提出的add-with-carry避免了乘法运算。算法的周期是2^121.

/* Implementation of a 32-bit KISS generator which uses no multiply instructions */ 

static unsigned int x=123456789,y=234567891,z=345678912,w=456789123,c=0; 

unsigned int JKISS32() 
{ 
    int t; 

    y ^= (y<<5); y ^= (y>>7); y ^= (y<<22); 

    t = z+w+c; z = w; c = t < 0; w = t&2147483647; 

    x += 1411392427; 

    return x + y + w; 
}


三.  恰当地给RNG提供种子(seed)

如若产生的数字具有很好的随机性,条件在于种子。平时,我们采用time的函数提供种子。问题在于time提供的种子值为32位,从而导致出现相同种子的概率变高。

一种简单的想法是组合出seed = (gettimeofday()+getpid()+gethostid()),来避免在两台不同的机器上产生一样的seed。

另外一种方法,从/dev/urandom中返回32位seed。

unsigned int devrand(void) 
{ 

	int fn; 

	unsigned int r; 

	fn = open("/dev/urandom", O_RDONLY); 

	if (fn == -1) 
		exit(-1); /* Failed! */ 

	if (read(fn, &r, 4) != 4) 
		exit(-1); /* Failed! */ 

	close(fn); 

	return r; 
} 

/* Initialise KISS generator using /dev/urandom */ 

void init_KISS() 
{ 

	x = devrand(); 

	while (!(y = devrand())); /* y must not be zero! */ 

	z = devrand(); 

	/* We don’t really need to set c as well but let's anyway… */ 
	/* NOTE: offset c by 1 to avoid z=c=0 */ 

	c = devrand() % 698769068 + 1; /* Should be less than 698769069 */ 
} 

 如果想了解的更多。还是看看原文吧。。。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值