在一些問題中,比如計算機**和模擬、密碼學等應用中,需要產生乙個隨機數數列來解決問題。
隨機數數列分為真隨機數數列和偽隨機數數列。真隨機數數列是完全不可**的,可以通過放射性衰變、電子裝置的熱噪音、宇宙射線的觸發時間等物理過程得到,但無法通過單純的軟體方式獲得;偽隨機數數列是可**的,嚴格意義上不具有隨機性質,通常用數學公式的方法獲得。
由於很多應用當中對「隨機」數列的要求並不十分嚴格,而且偽隨機數的產生較真隨機數更為廉價、高效,所以在大多數情況下只要產生統計分布較好的偽隨機數數列就能夠滿足應用要求。早期的偽隨機數生成演算法以平方取中法為主,現在則以線性同餘法為主要方式。下面我會就兩種方式分別給出例項,並以資料統計和圖形化的方式對偽隨機數生成演算法的效能進行檢驗。
正如數列需要有首項,產生偽隨機數需要乙個初值用來計算整個序列,這個初值被稱為「種子」。種子可以是乙個固定的值,也可以是根據當前系統狀態確定的值。c
語言用來產生偽隨機數的庫函式
rand()
的種子是固定的值,因此每次呼叫該函式產生的隨機數數列都是相同的。所以為了獲得隨機性更好的數列,種子應為乙個變數,該變數可以與當前系統時間、使用者對鍵盤或滑鼠操作情況
有關。這裡我將根據系統時間獲得種子。
**如下:
#include unsigned long ssecond,nowtime;
unsigned long seed;
long gettime() //獲得當前時間
在呼叫偽隨機數生成函式之前通過seed=gettime();
語句就完成了種子的初始化。
平方取中法是由馮·諾依曼在
1946
年提出的,其基本思想為:將數列中的第a(i)項(假設其有m
位)平方,取得到的2m位數(若不足2m位,在最高位前補
0)中間部分的m位數字,作為a(i)的下一項a(i+1),由此產生乙個偽隨機數數列。即:
x(i+1)=(10^(-m/2)*x(i)*x(i))mod(10^m)
平方取中法計算較快,但在實際應用時會發現該方法容易產生週期性明顯的數列,而且在某些情況下計算到一定步驟後始終產生相同的數甚至是零,或者產生的數字位數越來越小直至始終產生零。所以用平方取中法產生偽隨機數數列時不能單純使用公式,應該在計算過程中認為加入更多變化因素,比如根據前乙個數的奇偶性進行不同的運算,如果產生的數字位數減少時通過另一種運算使其恢復成m位。
**如下:
//編譯環境:code::blocks 10.05
//生成的數字範圍為[0,length-1]
long intlen(long in) //整數in的長度
return count;
}long power_10(long in) //10的in次冪
static unsigned long next = 1;
int rand(void)
void srand(unsigned int seed) //賦初值為種子
在vc
中rand()
函式定義如下:
int __cdecl rand (void)
c程式語言(第二版)(brian w. kernighan, dennis m. ritchie.)
中給出了一種適於c的
rand()
函式:
unsigned long next=1;
int rand(void)
void srand(unsigned int seed)
為了提高庫函式rand()
的效能,可以通過以下函式進行再次運算產生數列:
int rrand(int n)
以下為length=100
,利用c
的rand()
庫函式產生的隨機數序列:
41 67 34 0 69 24 78 58 62 64
5 45 81 27 61 91 95 42 27 36
91 4 2 53 92 82 21 16 18 95
47 26 71 38 69 12 67 99 35 94
3 11 22 33 73 64 41 11 53 68
47 44 62 57 37 59 23 41 29 78
16 35 90 42 88 6 40 42 64 48
46 5 90 29 70 50 6 1 93 48
29 23 84 54 56 40 66 76 31 8
44 39 26 23 37 38 18 82 29 41
可見,該演算法在連續計算
100次時取到了
0~99
之間的64
個不同的數。
為了提高演算法的均勻性,我找到了一種均勻度非常好的線性同餘演算法。c
**如下:
//編譯環境:code::blocks 10.05
//與平方取中法類似,種子根據當前系統時間獲取
unsigned long nowtime;
unsigned long seed;
long gettime() //獲得當前時間
#define length 100
//生成的數字範圍為[0,length-1]
int rand_xxty(void) //線性同餘法
以下為在5月18
日12時51
分27秒時刻以
length=100
產生的偽隨機數:
56 37 18 99 80 61 42 23 4 85
66 47 28 9 90 71 52 33 14 95
76 57 38 19 0 81 62 43 24 5
86 67 48 29 10 91 72 53 34 15
96 77 58 39 20 1 82 63 44 25
6 87 68 49 30 11 92 73 54 35
16 97 78 59 40 21 2 83 64 45
26 7 88 69 50 31 12 93 74 55
36 17 98 79 60 41 22 3 84 65
46 27 8 89 70 51 32 13 94 75
可見,該演算法在連續計算100
次時取到了
0~99
之間的所有的數。
length=500,以連續產生的兩個數字作為平面上點的橫座標與縱座標,計算
2000
次,做出圖形,可以看出該方法的特點,以及均勻性好的原因了:
從資料統計和所繪圖形來看,該演算法有極好的均勻性,但規律性較強,隨機性較差,適合應用在對均勻度要求較高,而對隨機性要求不高的問題中。
以上給出的幾種偽隨機數生成演算法各有優勢,而且效能都能達到一般應用的要求,具有一定的實用價值。
隨機數生成演算法
看到一些介紹隨機數生成演算法的文章,收集下來,有空深入了解下。c語言中偽隨機數生成演算法實際上是採用了 線性同餘法 具體的計算如下 xi xi 1 a c mod m 其中a,c,m都是常數 一般會取質數 當c 0時,叫做乘同餘法。srand 函式置的seed實際上會作為x0被代入上式中,然後每次呼...
隨機數生成演算法
這兩天沒事,就寫了寫數學課上老師說的那個 蒲豐投針實驗 的程式。接觸到了一些隨機數生成方面的東西,寫出來跟大家分享一下。對於計算機生成隨機數這個東西,以前有過一些淺顯的認識。只知道計算機不能生成真正的隨機數,只能用一定的方法來模擬隨機數,叫做偽隨機數。比如c語言裡面的rand 函式,就是乙個偽隨機數...
乙個偽隨機數生成演算法
乙個偽隨機數生成演算法 這幾天逛程式設計師論壇,發現了不少好帖子,增長了不少知識,現拿其中一則為例說明。某人提出乙個問題,說怎麼樣能生成一億個不重複的隨機數呢?問題表述起來很簡單,似乎只要弄明白什麼叫隨機數以及怎樣用電腦生成隨機數,就能解決問題了。這倆問題大多數程式設計師都會,我在這裡再表述一番。隨...