這兩天沒事,就寫了寫數學課上老師說的那個「蒲豐投針實驗"的程式。接觸到了一些隨機數生成方面的東西,寫出來跟大家分享一下。
對於計算機生成隨機數這個東西,以前有過一些淺顯的認識。只知道計算機不能生成真正的隨機數,只能用一定的方法來模擬隨機數,叫做偽隨機數。比如c語言裡面的rand()函式,就是乙個偽隨機數發生器。之前也知道有個叫做seed的東西,知道每次呼叫rand()之前都需要重置一下seed。以往的程式設計當中,一般都用系統時間來產生seed。但是seed是什麼東西,為什麼要用seed,則完全不清楚是怎麼一回事了。
xi = (xi-1 * a + c ) mod m
其中a,c,m都是常數(一般會取質數)。當c=0時,叫做乘同餘法。srand()函式置的seed實際上會作為x0被代入上式中,然後每次呼叫rand()函式都會用上一次產生的隨機值來生成新的隨機值。這樣我們可以看出實際上用rand()函式生成的是乙個遞推的序列,一切值都**於最初的seed。這就不難解釋為什麼當初始的seed取一樣的時候,得到的序列都相同。也就解釋了為什麼我們需要呼叫系統時間這種變化的值來充當seed了。
c語言裡面有rand_max這樣乙個巨集,定義了rand()所能得到的隨機值的範圍。在c裡可以看到rand_max被定義成0x7fff,也就是32767。據此我們可以推測rand()函式裡遞推式中m的值就是32767。據說在linux裡面這個值被定義的更大一些,也就是說linux裡生成的隨機值的範圍更大。
線性同餘法生成的隨機數的隨機性並不是很好,並不是真正的滿足均勻分布,僅僅能滿足一般的要求。 用這個做概率方面的模擬還是很有限的,網上搜到了一些關於計算機模擬的文章,提到了一些很專業的方法,比如蒙特卡洛方法等等。由於沒想深入,就沒往下看。
比較有意思的是在csdn上搜到了sjd163一篇文章講到了一種通過交換來得到隨機序列的方法。主要的依據是熱力學第二定律的熵增加原理。主要的思想是將有序的序列通過一定的交換將有序變成無序。思想類似於撲克牌的洗牌。假設撲克牌是從小到大的順序放好的,通過多次的洗牌之後撲克牌的順序性就逐漸消失,變的隨機。換句話說,系統的熵值變大。而且這種過程是不可逆的,只能從有序變成無序,不能從無序變成有序。
假設現在有乙個陣列,從小到大存放了一定數字。我們按照對插、倒排、交換、塊分割等等方法對這個陣列進行多輪的處理。原先包含在陣列中的順序關係就被我們逐漸打亂了。當然,為了使過程不可逆,我們可以在這些過程(比如交換)中引入簡單偽隨機值。通過n輪的處理之後,我們可以假設現在陣列已經變成了隨機序列。可以對結果進行概率分布的檢驗,如果檢驗不通過,重新進行處理,直到到達可以認為是隨機序列的程度。
看到這個方法的時候,我突然回想起來我似乎也曾將用過這種方法來生成隨機數。當時沒有多想,寫完就完了。沒想到居然還蘊含著這麼深刻的道理,pfpf。
可惜的是我用這兩種方法都進行了模擬,算出來的圓周率仍然不是很精確,最多也就到3.141左右。看來生成的隨機數還是不怎麼好。用於計算機模擬隨機數生成演算法應該會更好一些吧(據說用matlab生成的就比較好)
這裡是我的原始碼,有興趣可以看看。
我參考的一些資源和帖子都收集在mydiigo裡隨機數的tag中,也可以看看。
隨機數生成演算法
看到一些介紹隨機數生成演算法的文章,收集下來,有空深入了解下。c語言中偽隨機數生成演算法實際上是採用了 線性同餘法 具體的計算如下 xi xi 1 a c mod m 其中a,c,m都是常數 一般會取質數 當c 0時,叫做乘同餘法。srand 函式置的seed實際上會作為x0被代入上式中,然後每次呼...
隨機數生成演算法的研究
摘 要 本文通過流程圖和實際例程,較詳細地闡述了隨機數生成的演算法和具體的程式設計,分析了其符合演算法特徵的特性。1引言 在 資料結構 演算法分析與設計 科學模擬等方面都需要用到隨機數。由於在數學上,整數是離散型的,實數是連續型的,而在某一具體的工程技術應用中,可能還有數 據值的範圍性和是否可重複性...
一種隨機數生成演算法
隨機數生成類 class randnumber randnumber randnumber unsigned long s 0 else unsigned short randnumber random unsigned long n double randnumber frandom unsign...