隨機數生成算法-二談

生成均勻「隨機數」,一種生成均勻分佈數字的簡單方法

在實現粒子系統時,但願粒子能均勻分佈在某個範圍內,很容易想到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

相關文章
相關標籤/搜索