隨機數生成(一):均勻分佈

引言

許多應用中都需要用到隨機數,如物理仿真、統計採樣、密碼學、博彩等。隨機數一般可以通過兩種方法得到。一種是基於物理現象由硬件產生。由此得到的隨機數,在產生之前是不可預知的,因此,是真正的隨機數。另一種是通過計算機算法產生。通過算法產生的隨機數在本質是可以預知,但是在統計上,滿足一定的隨機性要求,因此一般稱作“僞隨機數”。
僞隨機數要比真正的隨機數更容易獲取,而且在大多數情況下都能滿足應用的要求。我們這裏只討論僞隨機數的生成算法,即隨機數生成器(Random Number Generator, RNG)。以下除特別指出外,我們提到的隨機數都是指僞隨機數。關於由硬件生成真正隨機數的方法可以參見這裏,一個產生真正隨機數的例子請參見這裏
經常地,隨機數在統計上需要滿足特定的分佈,如均勻分佈、正態分佈、指數分佈等等。一個好的隨機數生成器應該都夠高效地生成滿足待定分佈的隨機數序列。而產生的隨機數序列有多‘隨機“,又在在多大程度上符合特定分佈,則需要嚴格的理論證明和統計分析。但這裏,首先要記住一點,隨機序列的週期越長越好,雖然週期並不是評介隨機數算法的唯一重要標準。
文本介紹符合均勻分佈的隨機數生成的相關算法。(由於相關算法非常多,因此,這裏先介紹常用的若干種,有機會再逐漸補充。)有關隨機數產生質量的評估標準及其他分佈的隨機數生成算法,留待將來介紹。

——————————————————————————————

[a, b)間的均勻分佈隨機數x,滿足 f(x)=1/(b-a)x是離散的情況下,f(x)代表概率分佈函數;x是連續的情況下,f(x)代表概率密度函數。


線性同餘法(Linear Congruential Generator, LCG)

線性同餘法(Linear Congruential Generator, LCG)可能是最爲常見的一種隨機數生成算法,許多語言的標準庫中的隨機函數都是採用這種方法實現的。

線性同餘法通過以下遞歸式產生均勻分佈的隨機同序列{X}


其中,a、m爲正整數,b爲非負整數,ab都小於m;X0爲初始值(種子),是小於m的正整數。LCG產生的隨機序列的週期最大爲m,通常都會比m小。序列具有最大的週期m,當且僅當:

1.     bm互質;

2.     m所有質因子的乘積能夠整除(a-1);

3.     (a-1)是4的倍數,若m是4的倍數。

LCG算法產生的隨機序列對a、b、m的選取非常敏感;不恰當的選擇會使產生的隨機數質量很差。

標準C語言中rand()函數的參數設定爲:m = 231,a = 1103515245,b = 12345。每次遞歸過程,只截取X最高的16位作爲最終的隨機數輸出,因爲高位週期更長,由此產生的隨機數質量會更好。關於部分編程語言中隨機函數在用LCG實現時的具體參數設置可參見這裏

LCG非常容易實現,生成速度快,只需要很小的內存來維護狀態(通常僅需要4個或8個字節)。因而對於一般性的應用,LCG是首選。但LCG隨機數的週期短(32位的隨機數數,週期最多僅爲 232),隨性機一般。因而對於需要高質量隨機數的應用,如蒙特-卡羅算法,由LCG往往並不是理想的選擇。

進位相乘法(Multiply-with-carry,MWC)

MWC是一種與LCG在形式上類似的算法。它由如下遞歸式產生:


其中,cn代表第n代的進位,r是間隔。我們要用r個種子來初使化前n個數,另需要一個種子來初始化cr-1(cr-1 < a )。

要了解MWC的參數選擇,需要一定的數論和羣論知識,可以參看Marsaglia(MWC的提出者)的原帖說明和這份文檔及文獻[4][6], [8]給出了在給定不同模b的條件下,最佳參數選擇及證明。

在不增加計算量的情況下,MWC能夠給出比LCG長得多的週期。例如,同在模同爲2^32的條件下,MWC可以產生週期約爲10^318的序列,而LCG僅爲2^32(約爲10^10)。在適當的參數下,MWC可以產生週期長達10^453甚至更長的隨機序列。

這裏可以多提一下MWC的計算量問題。對多數CPU而言,32位的整數乘法在運算過程中會擴展到64位,低32作爲最後的結果,而高32位正是真正結果除以2^32的商,即我們這裏說的進位c。因此,相比LCG,MWC並不需要額外的運算來得到進位,只需取出高32位即可。

總之,MWC雖然在在理論上稍顯複雜,但設計分析上的複雜性在性能上有着驚人的回報。


線性反饋移位寄存器法(Linear feedback shift register, LFSR)

以上介紹的兩種方法,都是直接對整數進行操作, 而下面要介紹的LFSR方法的操作對象是位。同LCG相比,LFSR法也只需要佔用很少的內存,但卻能產生質量更高的隨機數。

LFSR是這樣一種移位寄存器:它的輸入位是它的當前各位狀態的線性函數,即Si+1,1=f(Si),f(·)爲關於Si的線性函數。LFSR最常用到了線性函數是對寄存器的某幾位進行異或(XOR)操作。

LFSR可以用硬件實現,也可以通過計算機的移位操作用軟件實現。有關前者可以參見這裏,關於軟件實現我們會在下面介紹。

斐波那契LFSR(Fabonacci LFSR)

F-LFSR利用斐波那契序列生成隨機序列,也稱作標準LFSR、多對一LFSR或外部異或門LFSR。下圖是一個4位的F-LFSR隨機數生成示意圖。移位寄存器每週期從左向右移一位。各個位從左到右依次編號爲b1、b2、b3、b4,則b1是輸入位,b4是輸出位。我們需要從輸入和輸出位之外,另外挑選出若干位,連同輸出位一起作爲反饋位。這裏我們選擇b3。線性反饋函數選擇爲各反饋位(包括輸出位)從右向左依次作XOR操作(例如,對16位寄存器,如果我們有b2、b4、b5作爲反饋位,則最終反饋函數應爲b16^b5^b4^b2)。
假如初始位狀態爲1-0-1-1,則反饋爲(1^1=0)作爲輸入,各位右移,狀態變爲0-1-0-1。再下一個週期,(1^0=1)作爲輸入,各位右移,狀態變爲1-0-1-0。依次類推。
顯然各位全爲0的狀態是不允許出現的,因爲它不能轉化爲其他的狀態。因此,n位的LFSR最多可以產生出2^n-1個不同狀態,即週期最長可達爲2^n-1。

 
4位F-LFSR


選擇不同的反饋位會得到不同週期長度的序列。能夠取得最長週期的選擇並不唯一,但它們需要滿足以下條件:
  1. 反饋位的個數爲偶數,通常2或4個反饋位就已經中夠長週期序列了;
  2. 反饋位的編號沒有公因數。
產生最長週期的反饋位的配置總是成對出現。例如,如果選擇[n, A, B, C]作爲反饋位,那麼,[n, n-C, n-B, n-A]的選擇也會產生一個最長的週期序列。
在FPGA硬件上的g實現參見這裏。以下代碼片斷示例了用C語言實現LFSR,代碼完成對LFSR的模擬,並得到週期:

#include <stdint.h>
uint16_t lfsr = 0xACE1u; //初始狀態
unsigned bit;            //反饋輸入
unsigned period = 0;     //生成序列的週期
do {
  /*反饋位: 16、14、13、11*/ 
 bit  = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1; //計算反饋輸入(s16^s14^s13^s11)  
 lfsr =  (lfsr >> 1) | (bit << 15); //移位,將反饋至輸入位
  ++period;
} while(lfsr != 0xACE1u);

伽羅華LFSR(Galois LFSR)

G-LFSR是另一種形式的LFSR,又稱爲組合LFSR、一對多LFSR或內部內部異或門LFSR。
每個時鐘週期,寄存器的各個位都向右移動一位;非反饋位直接移動,而反饋位在於輸出位進行異或操作後,再作右移。異或操作的結果是,當輸出位爲0時,反饋位相當於直接右移,而當輸出位爲1時,反饋位反轉(即1變爲0,0變爲1)後右移。

 
16位G-LFSR

如果我們採用與F-LFSR相反的編號方式(即最右位輸出位編號爲1,依次對各位編號),那麼當採用相同的配置時,G-LFSR產生的序列同F-LFSR相同。不同於F-LFSR,G-LFSR的各個異或門可以並行執行,因此,不論軟件或硬件實現,G-LFSR都更加快速。
一個關於G-LFRS的硬件實現可以參見這裏。以下C代碼實現了32位LFSR。

#include <stdint.h>
uint32_t lfsr = 1;
unsigned period = 0;
do {
  /* 反饋位: 32 31 29  */
  lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xD0000001u); 
  ++period;
} while(lfsr != 1u);

Mersenne twister(MT)

MT由日本學者Makoto Matsumoto和Takuji Nishimura提出。MT同LFSR同屬於一類稱爲GFSR(generalizedfeedback shift register)的方法。選擇合適的參數,MT方法可以生成周期長達2^19937-1(算法也因爲週期是梅森質數而得名)的32位整數,並且在高達623維下滿足均等分佈[7]。要得到64精度的整數,可以將兩個32位的隨機數組合。

MT算法需要634個字長的內存空間(在某些硬件下,這可能是一個缺點),運行速度與C語言的rand函數幾乎一樣快。 

MT算法的具體流程(包括C代碼)及參數選擇參見[7],各種語言的實現可以從這裏找到:http://en.wikipedia.org/wiki/Mersenne_twister#Implementations_in_various_languages,官方版本:http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html。基於SIMD計算優化的實現:http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html 。Python、Ruby、R、PHP、MATLAB中隨機函數的默認算法都是MT,而Boost C++ Library、NAG Numerical Library以及GNU的Scientific Library也實現都了用MT算法實現的RNG。GPU上CUDA版本curand(隨SDK發佈),另一個版本,但不如前者快。 

MT的一個缺點是啓動慢,當MT的種子各位含有較多的0時,需要較長時間跳出來,一般用LCG等初始化。有關這個改進可以參考[11],從http://en.wikipedia.org/wiki/Well_Equidistributed_Long-period_Linear 可以找到改進一些具體實現。


結語

雖然隨機數生成是計算機的一項常規任務,但很多情況下並沒有引起足夠的重視。Knuth曾說過,“查一查你所在機構的每臺計算機上安裝的函數庫,將裏面所有的隨機數生成函數都用更好的替換掉。儘量不要對你發現的結果太過於吃驚。”確實,許多隨機數函數質量不夠好,有些甚至可以說是很壞。當然,這並不意味着實現一個更好的版本是一件容易的事,這需要用到“真正的”數學!對於一般性的任務,一個設計良好的LCG方法可能已經足夠“隨機”了,並且LCG非常高效,不會佔用太多的內存空間。對於隨機性要求高的應用,MT一般是首要考慮的方法,但需要佔用相對較多的內存空間可能是它的一個不足(大多數情況下,這似乎根本不是個問題:)。其他的算法或者更適合於特定的應用,或者更便於在特定的硬件上實現。總之,當我們在使用隨機數的時候,我們最好知道自己在做什麼。


Refs

[1]Wikipedia:Random Number Generation.

[2]Wikipedia:Linear Congruential Generator.

[3]Wikipedia:Linear Feedback Shift Register.

[4]GeorgeMarsaglia and Arif Zaman: A New Class of Random Number Generators.(1991)

[5]PierreL'Ecuyer: Uniform random number generation.(1994)

[6]RaymondCouture and Pierre L'Ecuyer: Distribution properties of multiply-with-carryrandom number generators.(1997)

[7]MakotoMatsumoto and Takuji Nishimura: Mersenne twister: a 623-dimensionallyequidistributed uniform pseudo-random number generator.(1998)

[8]MarkGoresky: Efficient Multiply-with-Carry Random NumberGenerators with Maximal Period.(2008)

[9]GeorgeMarsaglia: Xorshift RNGs.(2003)

[10]LeeHowes: Efficient Random Number Generation and Application Using CUDA.(GPU Gems3 Chapter 37)

[11]PierreL'Ecuyer, François Panneton and Makoto Matsumoto: Improved Long-PeriodGenerators Based on Linear Recurrences Modulo 2.(2006)

[12]DavidB. Thomas, Lee Howes and Wayne Luk: A Comparison of CPUs, GPUs, FPGAs, andMassively Parallel Processor Arrays for Random Number Generation.(2009)

[13]C. J. A. Bastos-Filho, M. A. C. OliveiraJunior and A. D. Ramos: Impact of the Random Number Generator Quality onParticle Swarm Optimization Algorithm Running on Graphic Processor Units.(2010)
發佈了31 篇原創文章 · 獲贊 162 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章