matlab中的偽隨機數原理

iteye_11790發表於2013-10-05
要說matlab的隨機函式,就得先說說偽隨機數。不過我也只能從matlab應用的角度,從使用時的概念角度講講,梳理一下自己粗淺的理解。至於數理方面的,就沒認真看過。真正的隨機數是得通過現實世界中隨機發生的物理事件來產生的,如放射性物質隨機數發生器是通過某種放射性物質放射出的粒子數來獲得隨機數,還有通過電路產生高頻噪聲來獲得隨機數等。不過這種硬體隨機數發生器價格都比較貴,如使用比較廣泛的ComScire的隨機數發生器價格在895美元,約合人民幣6000元以上。但是很多軟體,PC機都需要使用隨機數,這麼貴的價格對一般應用來說不能每臺PC都買一個硬體隨機數發生器。在這種原因下,就出現了使用軟體方法來產生隨機數的演算法。通過軟體方法產生的隨機數都成為偽隨機數,因為它們都不是真正的隨機數。
所謂偽隨機數,就是找到一組數目巨大的數,這組數的出現符合一定的概率分佈,並且這組數能通過相應的隨機性測試,這樣我們就能使用這組數來湊合“頂替”真正的隨機數來應用了。但是由於其本質僅僅是用一組確定的數對真隨機數所表現出來的相關性質的近似,在有些場合下就無法滿足應用要求,或者說是“隨機性質不夠了”,如現在使用最廣泛的一種偽隨機數產生演算法,線性同餘演算法,無法滿足蒙特卡羅模擬對隨機性的要求。matlab預設使用的隨機數生成演算法Mersennetwister是目前較好的一種偽隨機數產生演算法,可以滿足很多場合的應用,如蒙特卡羅模擬等。所有滿足不同分佈的偽隨機數,都可以通過對均勻分佈偽隨機數的數學變換得到,均勻分佈偽隨機數的產生演算法,是偽隨機數產生演算法的根基,前面的線性同餘演算法,Mersennetwister演算法,都是均勻分佈偽隨機數的產生演算法。
偽隨機數的產生,一般都是這樣的情況,首先是選取種子,然後是在此種子基礎上根據具體的生成演算法計算得到一個偽隨機數,然後利用此偽隨機數再根據生成演算法遞迴計算出下一個偽隨機數,直到將所有不重複出現的偽隨機數全部計算出來。這個偽隨機數序列就是我們以後要用到的偽隨機數序列。上面的計算過程可以一次性計算完畢,也可以使用一次遞迴計算一次,每次生成的偽隨機數就是這個偽隨機數序列中的一個,不過不管怎麼樣,只要確定了種子,確定了生成演算法,這個序列就是確定的了。所謂種子,就是一個對偽隨機數計算的初始值。既然是確定的了,那麼當我們使用某種演算法計算給出一個偽隨機數,那麼下一次計算時出現的數也就是固定的,有人可能會問,既然是固定的,還有什麼隨機性?這就是偽隨機數的“偽”所在了。偽隨機數的“隨機”在於,雖然下次計算產生的數是一個固定的數,但是這種出現的模式,以及整個偽隨機數序列,卻能通過大部分隨機性測試實驗,這說明對隨機性測試實驗來說,偽隨機數的表現同真隨機數接近,這樣我們在一些不是很苛刻的應用場合,就能拿這組偽隨機數來用,使用時的外在表現同真隨機數是較近似的。
好了,現在才要說matlab的隨機函式,matlab的隨機函式產生的隨機數都是根據偽隨機數序列獲取的,在v7.7以上的版本中,有如下的偽隨機數產生器:Mersennetwister,Multiplicativecongruentialgenerator,MultiplicativelaggedFibonaccigenerator,Combinedmultiplerecursivegenerator,Shift-registergeneratorsummedwithlinearcongruentialgenerator,Modifiedsubtractwithborrowgenerator。相關的指令即可選擇不同的產生器。預設的情況下,matlab在啟動時總是將各個產生器的種子設為0,這樣造成編寫的包含隨機函式的程式每次執行的結果都是固定的,為了改變這種情況,可以將系統時間設定為種子(RandStream.setDefaultStream(RandStream('mt19937ar','Seed',sum(100*clock)))),這樣每次matlab啟動時種子設定的不同會使得計算得到的隨機序列不同。在7.7版本以上,隨機序列的生成通過RandStream物件來實現,與7.7以前的版本不同。
RandStream物件的使用可簡單總結如下:要生成一個隨機數,首先需要一個偽隨機數序列,這個序列通過設定種子和生成演算法來確定,RandStream的建構函式或RandStream.create方法即用來完成此任務。然後我們需要使用RandStream.setDefaultStream函式將確定好的序列物件設定為當前matlab使用的序列。然後通過rand等函式就可以用此序列生成隨機數了。當然也可以不用將其設定為預設序列,使用rand函式可以指定從哪個序列中生成隨機數:
stream=RandStream('mrg32k3a');
rand(stream,1,5)
使用RandStream.create函式可以建立獨立同分布的隨機序列,如
[s1,s2,s3]=RandStream.create('mrg32k3a','NumStreams',3);
r1=rand(s1,100000,1);r2=rand(s2,100000,1);r3=rand(s3,100000,1);
corrcoef([r1,r2,r3])
要使得前後兩次生成的隨機數保持一樣,可以將遞迴計算的過程中的偽隨機數狀態記錄下來,然後下一次計算總是基於這個記錄下來的偽隨機數狀態來進行,這樣每次計算得到的隨機數就總是相同的:
defaultStream=RandStream.getDefaultStream;
savedState=defaultStream.State;
u1=rand(1,5)
defaultStream.State=savedState;
u2=rand(1,5)
各個指令具體的使用方法可以通過helpdesk命令,搜尋RandStream來檢視。v7.7以上版本為了與舊版本保持相容,保留了原來如rand('state',0)這種偽隨機序列設定方法,稱之為legacymode,有關legacymode的內容也可以在RandStream項中找到。

相關文章