看到夏雪冬日的有關rand()和srand()產生隨機數的總結,挺好的,學習了,然后又有百度其他人的成果,系統總結一下。本文轉自夏雪冬日:http://www.cnblogs.com/heyonggang/archive/2012/12/12/2814271.html,Peng Lv:http://www.cnblogs.com/lvpengms/archive/2010/02/03/1663066.html#commentform。
要計算機產生一個隨機數不像扔色子一樣,計算機的每一步操作,就是執行一堆代碼,這些代碼是事先安排好的,所以計算機的產生行為是不具有隨機性和預測性的(當然這里說的是現階段的計算機體系,到未來的計算機的體系,未知),所以計算機產生的隨機數都不是真正意義上的隨機數,只是偽隨機數,他以一個真值(也稱為種子)作為初始條件,然后用一定的算法不停迭代產生隨機數。
庫函數中系統提供了兩個函數用於產生隨機數:srand()和rand();
rand函數:
頭文件<stdlib.h>
定義函數:int rand(void),
函數功能:產生隨機數,
函數說明:因為rand的內部是用線性同余法做的,不是真的隨機數,只不過因為其周期特別長,所以在一定范圍內可以看成是隨機的,rand()會返回一隨機值,范圍在0到RAND_MAX間,在調用此函數產生隨機數前,必須利用srand()設好隨機數種子,若沒有設隨機數種子,rand()在調用時會自動設隨機數種子為1。
返回值:返回0到RAND_MAX之間的整數值,RAND_MAX的范圍最少在32767之間(int),即雙字節(16位)。若unsigned int雙字節是65535,且0-RAND_MAX每個數字被選中的隨機率是相同的。 rand()產生的是假隨機數,每次執行時是相同的,若要不同以不同的值來初始化,初始化的函數就是srand()。
srand函數:
頭文件 <stdlib.h> ,
定義函數:void srand(unsigned int seed);
函數聲明:srand()用來設置rand()產生隨機數時的隨機數種子,參數seed必須是整數,通常可以用time(0)的返回值作為seed.如果每次seed都設置相同的值,rand()產生的隨機數值每次都一樣。
srand(unsigned)time(NULL))使用系統定時/計數器的值作為隨機種子每個種子對應一組根據算法預先生成的隨機數,所以在相同平台的環境下,不同時間產生的隨機數是不同的,相應的若將srand(unsigned)tima(NULL)改為任一常量,則無論何時運行,運行多少次得到的隨機數都是一組特定的序列,所以srand生成的隨機數是偽隨機數。但是,所謂的“偽隨機數”指的並不是假的隨機數,其實絕對的對技術只是一種假想狀態的隨機數,計算機只能生成相對的隨機數,而這些隨機數既是隨機的又是有規律的,一部分遵守一定規律,一部分則不遵守任何規律,總結來說就是:計算機產生偽隨機數而不是絕對的隨機數 (注:該內容來自:百度百科-rand函數)
在每次產生隨機序列前,先指定不同的種子,這樣計算出來的隨機序列就不完全相同了,而使用同種子相同的數調用rand()會導致相同的隨機數序列被生成。
例:
產生0到100之間的隨機數:
#include <stdlib.h> #include <stdio.h> #include <time.h> main() { int i,k; srand( (unsigned)time( NULL ) ); for( i = 0; i < 10;i++ ) { k=rand()%100+1; //rand()%100表示取100以內的隨機數,即取了隨機數后再對100取余 x=rand()%(Y-X+1)+X printf( " k=%d\n", k ); } }
由於rand產生的隨機數是0到rand_max,而rand_max是一個很大的數,那么要產生一個從X到Y的隨機數,可以這樣:s=rand()%(x-Y+1)+Y,這表示從X到Y范圍內的隨機數
系統在調用rand()之后就自動調用srand(),如果用戶在rand()之前調用srand()給參數seed指定一個值,那么rand()就會將seed的值作為產生偽隨機數的初始值,如果用戶在rand()前沒有調用srand(),系統會默認將1作為偽隨機數的初始值,如果給了一個定值,每次rand()產生的隨機數序列就一樣了,所以為了避免發生上述情況,通常用srand((unsigned)time(0))或者srand((unsigned)time(NULL))來產生種子,如果覺得時間間隔太小,可以在(unsigned)time(0)或者(unsigned)time(NULL)后面乘以某個合適值,如srand((unsigned)time(NULL)*10)。
另外,還可以通過 j=(int)(n*rand()/RAND_MAX+1),用來產生0到N之間的整數:
#include<stdio.h> #include<time.h> #include<stdlib.h> int main(void) { int i,j; for(i=0;i<10;i++) { j=1+(int)(10*rand()/(RAND_MAX+1)); printf("%d ",j); } printf("\n"); return 0; }
產生隨機數:
關於int x = rand() % n和 j=(int)(n*rand()/(RAND_MAX+1.0))的問題:
j=(int)(n*rand()/(RAND_MAX+1.0))就是隨機一個0到n之間不包括n的浮點數,然后強制轉換為就是0到9之間的整數了,這個跟x = rand() % n不同的地方就是,在多次隨機出來的結果,前者理論更平均一些,后者只是和n求余得到的結果,沒有前面的平均。
取模操作%是為了避免在某些情況下,某些偽隨機數生成器產生的數,低位不夠隨機的問題,這里涉及到二進制問題,因為取模在二進制意義上可能代表取得低位。
不過在針對自己的需要下,隨機數可以滿足所需的情況下,int x = rand() % n是完全可以代替j=(int)(n*rand()/(RAND_MAX+1.0)),畢竟前者的時間性能要好。
rand函數是真正的隨機數生成器,而srand()會設置提供rand()使用的隨機數種子。如果第一次調用rand()之前沒有調用srand(),那么系統會為你自動調用srand()。如下程序:
#include <stdlib.h> #include <stdio.h> #include <time.h> main() { int i,k; for( i = 0; i < 10;i++ ) { k=rand()%100+1; //rand()%100表示取100以內的隨機數,即取了隨機數后再對100取余 x=rand()%(Y-X+1)+X printf( " k=%d\n", k ); } }
一樣可以產生0到100間的隨機數。
另外,srand這個函數要放到循環外面,或者循環調用的外面,否則調用得到的是相同的數字。看下面例子:
#include<time.h> #include<stdlib.h> #include<stdio.h> main() { int i,j; for(i=0;i<10;i++) { srand((int)time(0)); j=1+int(rand()*100.0/(RAND_MAX+1.0)); printf("%d ",j); } }
在執行結束后,會發現所有a[i]是一樣的,srand放在循環里面,每產生一個隨機數之前,都調用srand,由於計算機運行很快,這段代碼總共執行不到1s,而srand()返回是以秒為單位,所以每次用time得到時間都是一樣的,這相當於使用同一個種子產生產生隨機序列,所以每次產生的隨機數相同,於是出現所有a[i]是一樣的,應該把srand放在循環外面。
如果計算偽隨機數序列的初始值(種子)相同,那么計算出來的偽隨機序列也完全相同,這個特性被有些軟件加密解密,加密時,用某個種子生產一個偽隨機數序列對數據進行處理;解密時,再利用種子數生產一個偽隨機序列對加密數據進行還原。(詳見:http://www.cnblogs.com/heyonggang/archive/2012/12/12/2814271.html)