摘 要:本文通過流程圖和實際例程,較詳細地闡述了隨機數生成的演算法和具體的程式設計,分析了其符合演算法特徵的特性。
1引言
在 資料結構、演算法分析與設計、科學模擬等方面都需要用到隨機數。由於在數學上,整數是離散型的,實數是連續型的,而在某一具體的工程技術應用中,可能還有數 據值的範圍性和是否可重複性的要求。因此,我們就整數隨機數和實數隨機數,以及它們的資料值的範圍性和是否可重複性,分別對其演算法加以分析和設計。以下以 visual basic 語言為工具,對整數隨機數生成問題加以闡述,而對於實數隨機數生成問題,只要稍加修改就可轉化為整數隨機數生成問題。
根據整數隨機數範圍性和是否可重複性,可分為:
(1)某範圍內可重複。
(2)某範圍內不可重複。
(3)列舉可重複。
(4)列舉不可重複。
所 謂範圍,是指在兩個數n1和n2之間。例如,在100和200之間這個範圍,那麼,只要產生的整數隨機數n滿足100≤n≤200,都符合要求。所謂枚 舉,是指有限的、已知的、若干個不連續的整數。例如,34、20、123、5、800這5個整數就是一種列舉數,也就是單獨可以乙個個確定下來。
2 某範圍內可重複
在visual basic 語言中,有乙個隨機數函式rnd。
語法:rnd[(number)]。
引數number 可選,number 的值決定了 rnd 生成隨機數的方式。rnd 函式返回小於 1 但大於或等於 0 的值。
如果 number 為
rnd 生成
小於零
每次都相同的數字,並將 number 用作種子。
大於零
序列中的下乙個隨機數。
等於零
最近生成的數字。
未提供
序列中的下乙個隨機數。
在呼叫 rnd 之前,先使用無引數的 randomize 語句初始化隨機數生成器,該生成器具有乙個基於系統計時器的種子。
若要生成某給定範圍內的隨機整數,可使用以下公式:
int((upperbound - lowerbound + 1) * rnd + lowerbound)
這裡,upperbound 是此範圍的上限,而 lowerbound 是範圍的下限。
程式流程圖:
程式例程:下面是乙個生成10個10~20之間隨機數的例子。
private sub command1_click()
lowerbound = 10
upperbound = 20
randomize
for i = 1 to 10
random = int((upperbound - lowerbound + 1) * rnd + lowerbound)
debug.print random;
next
debug.print
end sub
執行結果:12 10 20 20 17 17 18 14 12 20
3 某範圍內不可重複
要產生一定範圍內不可重複的隨機數,按通常的設計是把曾經生成的隨機數儲存起來作為歷史資料。產生乙個新的隨機數後在歷史資料搜尋,若找到就重新產生乙個新的再重複資料搜尋;否則就認為已經找到了乙個新的不同隨機數。
例如,要由計算機隨機產生10個101~200之間互不相同的數。
程式流程圖:
程式:
private sub command2_click()
dim random(10) as integer
lowerbound = 101
upperbound = 200
randomize
for i = 1 to 10
do
r = int((upperbound - lowerbound + 1) * rnd + lowerbound)
yes = 0
for j = 1 to i - 1
if r = random(j) then yes = 1: exit for
next
loop while yes = 1
random(i) = r
debug.print r;
next
debug.print
end sub
執行結果:199 174 147 126 120 190 192 146 122 111
粗 看起來,上面的程式似乎沒有什麼問題,在執行過程中程式也能夠通過。但,仔細分析我們就會發現問題出在乙個新產生的隨機數是否已經存在的判定上。既然是隨 機數,那麼從數學的角度來說在概率上,每次產生的隨機數 r就有可能相同,儘管這種可能性很小,但確是乙個邏輯性與正確性的問題。因此,每次產生的新的隨機數r都有可能是陣列random的前i-1個數中的某一 個,也就是說程式在執行過程中由此可能會導致死迴圈,那麼,能否找到乙個不在陣列random中的隨機數r的工作就變得不確定了。從演算法的角度來講,在理 論上,程式失去了有窮性、有效性和確定性。
什麼是演算法?通常人們將演算法定義為乙個有窮的指令集,這些指令為解決某一特定任務規定了乙個運算序列。乙個演算法應當具有以下特徵:
(1)輸入:乙個演算法必須有0個或多個輸入。它們是演算法開始運算前給予演算法的量。這些輸入取自於特定的物件的集合。它們可以使用輸入語句由外部提供,也可以使用置初值語句或賦值語句在演算法內提供。
(2)輸出:乙個演算法應有1個或多個輸出,輸出的量是演算法計算的結果。
(3)確定性:演算法的每一步都應確切地、無歧義地定義。對於每一種情況,需要執行的動作都應嚴格地、清晰地規定。
(4)有窮性:乙個演算法無論在什麼情況下,都應在執行有窮步後結束。
(5)有效性:演算法中每一條運算都必須是足夠基本的。就是說,它們原則上都能精確地執行,甚至人們只用紙和筆做有限次運算就能完成。
一 般來說,我們所編寫的程式都是在特定演算法基礎上設計出來的,程式常常與演算法是相互對應的,在沒有特殊的情況下,程式也應當具有以上五個特徵。但,也有一些 程式在設計中,人們由於疏忽會想當然地認為,程式只要編寫出來一般都會自然地符合演算法的五個特徵,這是應當引為注意的。
那麼,應該如何對其進行改進,使其符合演算法的五個特徵呢?
仍然以上述由計算機隨機產生10個101~200之間互不相同的數為例進行闡述。
首先,把要產生的所有數放到乙個陣列a中。令upperbound 是此範圍的上限,而 lowerbound 是範圍的下限。
第 二,每次隨機生成陣列a的乙個下標subscript,然後取出它所對應的資料,將陣列a的最後乙個數放到下標subscript的位置,同時將陣列a長 度減1。儘管前若干次生成的下標subscript隨機數有可能相同,但,因為每一次都把最後乙個數填到取出的位置,因此,相同下標subscript對 應的數卻絕不會相同,每一次取出的數都不會一樣,這樣,就保證了演算法的確定性、有效性、有窮性。
程式流程圖:
程式:
private sub command3_click()
dim a(10), b(100) as integer
lowerbound = 101
upperbound = 200
for i = 1 to upperbound - lowerbound + 1
b(i) = lowerbound + i - 1
next
randomize
length = upperbound - lowerbound + 1
for i = 1 to 10
subscript = int(length * rnd + 1)
r = b(subscript)
b(script) = b(length)
length = length - i
a(i) = r
debug.print a(i);
next
debug.print
end sub
執行結果:195 153 148 183 149 101 137 172 126 110
4 列舉可重複
這種隨機數的生成比較簡單,只要把各個列舉數放入乙個陣列中儲存起來,然後隨機生成陣列的下標,最後取出對應下標下的陣列的值即可。
流程圖和程式可參考前面的論述。
5 列舉不可重複
首先把各個列舉數放入乙個陣列中儲存起來,其它的處理方法完全類似於某範圍內不可重複隨機數的方法。
6 結束語
上述演算法具有很高的應用價值與理論價值。在計算機資料結構、演算法分析與設計、科學模擬等方面需要隨機數的應用中,都可使用該演算法。
[1] 《visual basic程式設計教程》北京:機械工業出版社,2002.2.1
[2] 嚴蔚敏《資料結構》(第二版)北京:清華大學出版社,1999
隨機數生成演算法
看到一些介紹隨機數生成演算法的文章,收集下來,有空深入了解下。c語言中偽隨機數生成演算法實際上是採用了 線性同餘法 具體的計算如下 xi xi 1 a c mod m 其中a,c,m都是常數 一般會取質數 當c 0時,叫做乘同餘法。srand 函式置的seed實際上會作為x0被代入上式中,然後每次呼...
隨機數生成演算法
這兩天沒事,就寫了寫數學課上老師說的那個 蒲豐投針實驗 的程式。接觸到了一些隨機數生成方面的東西,寫出來跟大家分享一下。對於計算機生成隨機數這個東西,以前有過一些淺顯的認識。只知道計算機不能生成真正的隨機數,只能用一定的方法來模擬隨機數,叫做偽隨機數。比如c語言裡面的rand 函式,就是乙個偽隨機數...
一種隨機數生成演算法
隨機數生成類 class randnumber randnumber randnumber unsigned long s 0 else unsigned short randnumber random unsigned long n double randnumber frandom unsign...