1. 程式人生 > >C++-隨機數的產生

C++-隨機數的產生

一、隨機數

  以前學C語言的時候感覺隨機數沒啥用的,現在想想是自己無知啦,在幫人做一個專案的時候發現隨機數還是相當有用的,我們可以利用隨機數來生成大量的測試資料。

  有兩種方法可以讓你的程式每次執行結果不同:

1.讓使用者輸入不同的資料(或者從檔案中讀取不同的資料);
2.對使用者輸入的相同資料採取不同的處理方式,使其執行結果不同。

  大多數情況下,第一種方法是非常好的,使用者總是希望他們程式的結果是可預測的。比如當編寫一個文字編輯器或者網頁瀏覽器時,你會希望程式在使用者每次輸入一段文字或網址時執行同樣的操作,而不是由瀏覽器隨機決定訪問哪個頁面,除非是使用StumbleUpon1。
1StumbleUpon是一個能讓你“偶遇”有趣網頁的網站:http://www.stumbleupon.com/。

  但在某些情況,每次執行相同操作並不是一個好的處理方式。例如,很多電腦遊戲依賴隨機,俄羅斯方塊便是一個典型的例子,如果每次遊戲方塊的下落順序都相同,使用者便會記住下落順序,因為可以預測接下來會出現什麼方塊,所以得分會一次比一次高。最後遊戲和背誦圓周率的千位小數沒啥不同。為了讓俄羅斯方塊遊戲更有意思,程式需要隨機選擇下一次方塊的形狀和朝向。

  為了實現這個功能,計算機需要生成隨機數。因為計算機會準確執行命令,當我們執行相同的操作時計算機總會返回同樣的結果。這就很難生成真正的隨機數。不過沒有必要生成真的隨機數。生成像隨機數的數也能達到目的,這就是偽隨機數

  要生成偽隨機數,計算機需要一個種子

,利用數學變換將種子轉換成另一個值。新值再成為下一個種子。如果程式每次採用不同的種子,程式便永遠不會生成相同的資料序列。這裡使用的數學轉換需要特別挑選,要讓所有數字的生成概率相等但又不會有明顯的計算模型。(例如,它不會只是每次對數字加1。)

  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()生成隨機數,無形參,每呼叫一次返回值一個