C++-隨機數的產生
一、隨機數
以前學C語言的時候感覺隨機數沒啥用的,現在想想是自己無知啦,在幫人做一個專案的時候發現隨機數還是相當有用的,我們可以利用隨機數來生成大量的測試資料。
有兩種方法可以讓你的程式每次執行結果不同:
1.讓使用者輸入不同的資料(或者從檔案中讀取不同的資料);
2.對使用者輸入的相同資料採取不同的處理方式,使其執行結果不同。
大多數情況下,第一種方法是非常好的,使用者總是希望他們程式的結果是可預測的。比如當編寫一個文字編輯器或者網頁瀏覽器時,你會希望程式在使用者每次輸入一段文字或網址時執行同樣的操作,而不是由瀏覽器隨機決定訪問哪個頁面,除非是使用StumbleUpon1。
1StumbleUpon是一個能讓你“偶遇”有趣網頁的網站:http://www.stumbleupon.com/。
但在某些情況,每次執行相同操作並不是一個好的處理方式。例如,很多電腦遊戲依賴隨機,俄羅斯方塊便是一個典型的例子,如果每次遊戲方塊的下落順序都相同,使用者便會記住下落順序,因為可以預測接下來會出現什麼方塊,所以得分會一次比一次高。最後遊戲和背誦圓周率的千位小數沒啥不同。為了讓俄羅斯方塊遊戲更有意思,程式需要隨機選擇下一次方塊的形狀和朝向。
為了實現這個功能,計算機需要生成隨機數。因為計算機會準確執行命令,當我們執行相同的操作時計算機總會返回同樣的結果。這就很難生成真正的隨機數。不過沒有必要生成真的隨機數。生成像隨機數的數也能達到目的,這就是偽隨機數。
要生成偽隨機數,計算機需要一個種子
C++提供了所有的功能。你無需關心數學轉換,C++中有相關的函式實現。所有你要做的只是提供隨機種子,使用當前時間作種子即可。讓我們看一下細節:
1.1 隨機數的產生
C++有兩個函式,一個是設定隨機種子,另一個是用種子產生隨機數:
1 void srand (int seed);
srand函式將某個數字設定為種子。在程式開頭處需要呼叫一次srand。使用srand的典型方法是把time函式的結果作為引數,time函式返回一個代表當前時間的數值。
time函式返回從1970年1月1日起到現在的秒數。這個規則源自於Unix作業系統,有時它稱為Unix time。大多數情況下,時間儲存在32位有符號整型中。
隨著時間的增加,秒數會超過整型可表示的範圍,最後將以負數結尾表示過去的時間。超過整型數的現象將發生在2038年,它引起了對“2038年問題”(Year2038 Problem)的討論,使用Unix time的計算機程式將會把2038年當做1901年處理。詳情請參考:
http://en.wikipedia.org/wiki/Year_2038_problem。
1 srand ( time ( NULL ) );
目前你不用瞭解NULL引數,先就照著這麼寫;
如果連續呼叫srand,程式會反覆地更新隨機數發生器種子,因為連續呼叫的時間序列非常相近,生成的隨機數也會很相近。(使用srand必須包含cstdlib標頭檔案,使用time函式必須包含ctime標頭檔案。
1 #include <cstdlib> 2 #include <ctime> 3 int main () 4 { 5 //在最開始處呼叫一次 6 srand( time( NULL ) ); 7 }
參照下面原型呼叫rand函式來獲取隨機數。
1 int rand ();
注意rand函式沒有任何引數,僅有一個返回值。讓我們將返回值輸出出來。
1 #include <cstdlib> 2 #include <ctime> 3 #include <iostream> 4 using namespace std; 5 int main () 6 { 7 //在最開始處呼叫一次 8 srand( time( NULL ) ); 9 cout << rand() << '\n'; 10 }
C++有一個返回除法餘數的操作符(如4/3商為1,餘數為1)——模數運算子。如果你沒有注意到也不要緊,人們總是自動遮蔽數學函式。但模數非常有用。因為被4整除的餘數的範圍是0~3。如果用rand函式返回的隨機數除以所需數字的範圍長度(即範圍內數的數量),便會獲得0到最大範圍之間的值(不包含最大值)。
1 #include <ctime> 2 #include <cstdlib> 3 #include <iostream> 4 using namespace std; 5 int randRange (int low, int high) 6 { 7 //先獲取隨機數,再處理得到從0到所需數字範圍長度的值,然後加上最小值 8 return rand() % ( high - low + 1 ) + low; 9 } 10 int main () 11 { 12 srand( time( NULL ) ); 13 for ( int i = 0; i < 1000; ++i ) 14 { 15 cout << randRange( 4, 10 ) << '\n'; 16 } 17 }
這段程式有兩點需要注意的地方。首先,我們必須對high-low加1,舉例說明原因,設想目標範圍是0到10,當中有11種可能出現的值。減法獲得的是兩個值之間的差值,比範圍內值的數量少1,因此必須加1。其次,注意我們需要加上目標範圍的最小值,設想如果想獲取10到20之間的數,通過上面的方法只能獲取0到10之間的隨機數,再加10才能將範圍設定到10到20之間。
參考文獻:c++現代程式設計方法
小結:
-我們產生隨機數不用自己去編寫數學變換公式,直接呼叫兩個隨機函式
-time(NULL)返回當前距離1970年的秒數,將其作為引數傳遞給srand生成隨機種子;
-rand()生成隨機數,無形參,每呼叫一次返回值一個