随机数生成算法-二谈

生成均匀“随机数”,一种生成均匀分布数字的简单方法

在实现粒子系统时,但愿粒子能均匀分布在某个范围内,很容易想到C++标准的随机数发生器(实际是产生的是伪随机数,通常使用所谓的线型同余法),但随机数的“均匀分布”须要无限多个样本,才能表现出均匀分布的特征,在一段短的时间内,常常产生一些不均匀。(若是是均匀的,那么买彩票就能根据之前出现的号码推断之后出现的号码。)
 
若是用随机数生成平面内的粒子坐标,将会获得不太均匀的分布,这里通过一番思考,想出来这个办法:

1.若是须要的是一维空间的均匀分布的位置,那么但愿是每2次产生的数字分别属于2个象限,在一个象限内,数字某个1/2象限,在1/2象限里,又轮流出如今1/4象限内,依此类推。
2.若是须要的是二维空间的均匀分布的位置,那么但愿是每4次产生的数字分别属于4个象限,在一个象限内,获得的数字轮流属因而此象限的某个1/4,依此类推。

在n维空间内,空间能够逐级分红2^n个象限,
很容易想到,在一维空间里,用二进制数字来表示位置,若是是4位二进制数字,能够表示32个数字,咱们能够把空间分割成32份,数字是这样变化的:
0000
0001
0010
0011
0100
0101
0110
0111
...
在最低位,数字在较小范围内是均匀分布的,第2位在4个数字的空间内均匀分布,第3位在8个数字内是均匀分布。。。
若是把生成的数字限制在0~15之间,那么这样连续的数字,每一个都会出现一次,是绝对均匀分布的。但在一段时间内,数字分布是不均匀的。那么均匀分布是什么样的呢,应该这样,每次产生一个数字,数字落在左右两边的次数最多相差为1,也就是说,数字轮流出如今左右两边,若是用最低位表示左右,那么很显然能知足要求。
若是咱们用数字直接表示位置,0~0111在左边,1000~1111在右边,既最高位决定左右,这样问题解决了,把一个逐渐增大的数字(0~15)的各位翻转,最高位变成最低位,次高位变成第2位。。。 那么这个数字能够均匀出如今左右,那么是否在任意范围内均匀呢?

咱们把结果的范围0~15分红任意多份,能够看到,当产生了N个数字(按顺序取0~255,而后翻转)时,数字出如今任何两个部分的的次数相差不超过1。
html


1unsigned long bit_reverse(unsigned long n)
2
{
3       n = ((n >> 1& 0x55555555| ((n << 1& 0xaaaaaaaa
);
4       n = ((n >> 2& 0x33333333| ((n << 2& 0xcccccccc
);
5       n = ((n >> 4& 0x0f0f0f0f| ((n << 4& 0xf0f0f0f0
);
6       n = ((n >> 8& 0x00ff00ff| ((n << 8& 0xff00ff00
);
7       n = ((n >> 16& 0x0000ffff| ((n << 16& 0xffff0000
); 
8       return
 n;
9}


对于4位二进制数,输入0~15,能够获得这样的结果:
0
        8
    4
            12
  2
          10
      6
              14
 1
         9
     5
             13
   3
           11
       7
               15

这种方法产生的数字能够用在粒子系统发生器中,或许也能够用在其余须要均匀分布资源的地方。
若是须要获得二维空间内的随机位置,能够用除法和求余的方法得到水平和垂直坐标。
刚才提到粒子系统,在粒子系统中,有时候须要在球面上产生均匀分布的粒子,能够用到上面的方法,可是还不够,下次再把方法写下来。

附:线型同余法示例代码:
int f() 
{  static int r; 
   r = ( 25173*r+13849 ) % 65536; 
   return r; 
}
spa

相关文章
相关标签/搜索