C和C++隨機數(shù)或字符串生成源碼.doc
《C和C++隨機數(shù)或字符串生成源碼.doc》由會員分享,可在線閱讀,更多相關(guān)《C和C++隨機數(shù)或字符串生成源碼.doc(10頁珍藏版)》請在裝配圖網(wǎng)上搜索。
1. 基本函數(shù) 在C語言中取隨機數(shù)所需要的函數(shù)是: int rand(void);void srand (unsigned int n); rand()函數(shù)和srand()函數(shù)被聲明在頭文件stdlib.h中,所以要使用這兩個函數(shù)必須包含該頭文件: #include 2. 使用方法 rand()函數(shù)返回0到RAND_MAX之間的偽隨機數(shù)(pseudorandom)。RAND_MAX常量被定義在stdlib.h頭文件中。其值等于32767,或者更大。 srand()函數(shù)使用自變量n作為種子,用來初始化隨機數(shù)產(chǎn)生器。只要把相同的種子傳入srand(),然后調(diào)用rand()時,就會產(chǎn)生相同的隨機數(shù)序列。因此,我們可以把時間作為srand()函數(shù)的種子,就可以避免重復(fù)的發(fā)生。如果,調(diào)用rand()之前沒有先調(diào)用srand(),就和事先調(diào)用srand(1)所產(chǎn)生的結(jié)果一樣。 /* 例1:不指定種子的值 */ for (int i=0; i10; i+) printf(%d , rand()%10); 每次運行都將輸出:1 7 4 0 9 4 8 8 2 4 /* 例2:指定種子的值為1 */ srand(1);for (int i=0; i10; i+)printf(%d , rand()%10); 每次運行都將輸出:1 7 4 0 9 4 8 8 2 4 例2的輸出結(jié)果與例1是完全一樣的。 /* 例3:指定種子的值為8 */srand(8);for (int i=0; i10; i+)printf(%d , rand()%10); 每次運行都將輸出:4 0 1 3 5 3 7 7 1 5 該程序取得的隨機值也是在0,10)之間,與srand(1)所取得的值不同,但是每次運行程序的結(jié)果都相同。 /* 例4:指定種子值為現(xiàn)在的時間 */srand(unsigned)time(NULL);for (int i=0; i10; i+)printf(%d , rand()%10); 該程序每次運行結(jié)果都不一樣,因為每次啟動程序的時間都不同。另外需要注意的是,使用time()函數(shù)前必須包含頭文件time.h。 3. 注意事項 求一定范圍內(nèi)的隨機數(shù)。 如要取0,10)之間的隨機整數(shù),需將rand()的返回值與10求模。 randnumber = rand() % 10; 那么,如果取的值不是從0開始呢?你只需要記住一個通用的公式。 要取a,b)之間的隨機整數(shù)(包括a,但不包括b),使用: (rand() % (b - a) + a 偽隨機浮點數(shù)。 要取得01之間的浮點數(shù),可以用: rand() / (double)(RAND_MAX) 如果想取更大范圍的隨機浮點數(shù),比如0100,可以采用如下方法: rand() /(double)(RAND_MAX)/100) 其他情況,以此類推,這里不作詳細(xì)說明。 當(dāng)然,本文取偽隨機浮點數(shù)的方法只是用來說明函數(shù)的使用辦法,你可以采用更好的方法來實現(xiàn)。 舉個例子,假設(shè)我們要取得010之間的隨機整數(shù)(不含10本身): 大家可能很多次討論過隨機數(shù)在計算機中怎樣產(chǎn)生的問題,在這篇文章中,我會對這個問題進(jìn)行更深入的探討,闡述我對這個問題的理解。 首先需要聲明的是,計算機不會產(chǎn)生絕對隨機的隨機數(shù),計算機只能產(chǎn)生“偽隨機數(shù)”。其實絕對隨機的隨機數(shù)只是一種理想的隨機數(shù),即使計算機怎樣發(fā)展,它也不會產(chǎn)生一串絕對隨機的隨機數(shù)。計算機只能生成相對的隨機數(shù),即偽隨機數(shù)。 偽隨機數(shù)并不是假隨機數(shù),這里的“偽”是有規(guī)律的意思,就是計算機產(chǎn)生的偽隨機數(shù)既是隨機的又是有規(guī)律的。怎樣理解呢?產(chǎn)生的偽隨機數(shù)有時遵守一定的規(guī)律,有時不遵守任何規(guī)律;偽隨機數(shù)有一部分遵守一定的規(guī)律;另一部分不遵守任何規(guī)律。比如“世上沒有兩片形狀完全相同的樹葉”,這正是點到了事物的特性,即隨機性,但是每種樹的葉子都有近似的形狀,這正是事物的共性,即規(guī)律性。從這個角度講,你大概就會接受這樣的事實了:計算機只能產(chǎn)生偽隨機數(shù)而不能產(chǎn)生絕對隨機的隨機數(shù)。 那么計算機中隨機數(shù)是怎樣產(chǎn)生的呢?有人可能會說,隨機數(shù)是由“隨機種子”產(chǎn)生的。沒錯,隨機種子是用來產(chǎn)生隨機數(shù)的一個數(shù),在計算機中,這樣的一個“隨機種子”是一個無符號整形數(shù)。那么隨機種子是從哪里獲得的呢? 下面看這樣一個C程序: /rand01.c#includestatic unsigned int RAND_SEED;unsigned int random(void) RAND_SEED=(RAND_SEED*123+59)%65536; return(RAND_SEED);void random_start(void) int temp2; movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4); RAND_SEED=temp0;main() unsigned int i,n; random_start(); for(i=0;i10;i+) printf(%ut,random();printf(n); 這個程序(rand01.c)完整地闡述了隨機數(shù)產(chǎn)生的過程: 首先,主程序調(diào)用random_start()方法,random_start()方法中的這一句我很感興趣: movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4); 這個函數(shù)用來移動內(nèi)存數(shù)據(jù),其中FP_SEG(far pointer to segment)是取temp數(shù)組段地址的函數(shù),F(xiàn)P_OFF(far pointer to offset)是取temp數(shù)組相對地址的函數(shù),movedata函數(shù)的作用是把位于0040:006CH存儲單元中的雙字放到數(shù)組temp的聲明的兩個存儲單元中。這樣可以通過temp數(shù)組把0040:006CH處的一個16位的數(shù)送給RAND_SEED。 random用來根據(jù)隨機種子RAND_SEED的值計算得出隨機數(shù),其中這一句: RAND_SEED = (RAND_SEED*123+59)%65536; 是用來計算隨機數(shù)的方法,隨機數(shù)的計算方法在不同的計算機中是不同的,即使在相同的計算機中安裝的不同的操作系統(tǒng)中也是不同的。我在linux和windows下分別試過,相同的隨機種子在這兩種操作系統(tǒng)中生成的隨機數(shù)是不同的,這說明它們的計算方法不同。 現(xiàn)在,我們明白隨機種子是從哪兒獲得的,而且知道隨機數(shù)是怎樣通過隨機種子計算出來的了。那么,隨機種子為什么要在內(nèi)存的0040:006CH處取?0040:006CH處存放的是什么? 學(xué)過計算機組成原理與接口技術(shù)這門課的人可能會記得在編制ROM BIOS時鐘中斷服務(wù)程序時會用到Intel 8253定時/計數(shù)器,它與Intel 8259中斷芯片的通信使得中斷服務(wù)程序得以運轉(zhuǎn),主板每秒產(chǎn)生的18.2次中斷正是處理器根據(jù)定時/記數(shù)器值控制中斷芯片產(chǎn)生的。在我們計算機的主機板上都會有這樣一個定時/記數(shù)器用來計算當(dāng)前系統(tǒng)時間,每過一個時鐘信號周期都會使記數(shù)器加一,而這個記數(shù)器的值存放在哪兒呢?沒錯,就在內(nèi)存的0040:006CH處,其實這一段內(nèi)存空間是這樣定義的: TIMER_LOW DW ? ;地址為 0040:006CH TIMER_HIGH DW ? ;地址為 0040:006EH TIMER_OFT DB ? ;地址為 0040:0070H 時鐘中斷服務(wù)程序中,每當(dāng)TIMER_LOW轉(zhuǎn)滿時,此時,記數(shù)器也會轉(zhuǎn)滿,記數(shù)器的值歸零,即TIMER_LOW處的16位二進(jìn)制歸零,而TIMER_HIGH加一。rand01.c中的 movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4); 正是把TIMER_LOW和TIMER_HIGH兩個16位二進(jìn)制數(shù)放進(jìn)temp數(shù)組,再送往RAND_SEED,從而獲得了“隨機種子”。 現(xiàn)在,可以確定的一點是,隨機種子來自系統(tǒng)時鐘,確切地說,是來自計算機主板上的定時/計數(shù)器在內(nèi)存中的記數(shù)值。這樣,我們總結(jié)一下前面的分析,并討論一下這些結(jié)論在程序中的應(yīng)用: 1.隨機數(shù)是由隨機種子根據(jù)一定的計算方法計算出來的數(shù)值。所以,只要計算方法一定,隨機種子一定,那么產(chǎn)生的隨機數(shù)就不會變。 看下面這個C+程序: /rand02.cpp#include #include using namespace std;int main() unsigned int seed = 5; srand(seed); unsigned int r = rand(); cout r endl; 在相同的平臺環(huán)境下,編譯生成exe后,每次運行它,顯示的隨機數(shù)都是一樣的。這是因為在相同的編譯平臺環(huán)境下,由隨機種子生成隨機數(shù)的計算方法都是一樣的,再加上隨機種子一樣,所以產(chǎn)生的隨機數(shù)就是一樣的。 2.只要用戶或第三方不設(shè)置隨機種子,那么在默認(rèn)情況下隨機種子來自系統(tǒng)時鐘(即定時/計數(shù)器的值) 看下面這個C+程序: /rand03.cpp#include #include using namespace std;int main() srand(unsigned)time(NULL); unsigned int r = rand(); cout r endl; return 0; 這里用戶和其他程序沒有設(shè)定隨機種子,則使用系統(tǒng)定時/計數(shù)器的值做為隨機種子,所以,在相同的平臺環(huán)境下,編譯生成exe后,每次運行它,顯示的隨機數(shù)會是偽隨機數(shù),即每次運行顯示的結(jié)果會有不同。 3.建議:如果想在一個程序中生成隨機數(shù)序列,需要至多在生成隨機數(shù)之前設(shè)置一次隨機種子。 看下面這個用來生成一個隨機字符串的C+程序: /rand04.cpp#include#includeusing namespace std;int main() int rNum,m = 20; char *ch = new charm;for ( int i = 0; i m; i+ ) /大家看到了,隨機種子會隨著for循環(huán)在程序中設(shè)置多次 srand(unsigned)time(NULL)*j);/j是后加的外層循環(huán) rNum = 1+(int)(rand()/(double)RAND_MAX)*36); /求隨機值switch (rNum) case 1: chi=a; break ; case 2: chi=b; break ; case 3: chi=c; break ; case 4: chi=d; break ; case 5: chi=e; break ;case 6: chi=f; break ; case 7: chi=g; break ; case 8: chi=h; break ; case 9: chi=i; break ; case 10: chi=j; break ; case 11: chi=k; break ; case 12: chi=l; break ;case 13: chi=m; break ; case 14: chi=n; break ; case 15: chi=o;break ; case 16: chi=p; break ; case 17: chi=q; break ;case 18: chi=r; break ;case 19: chi=s; break ; case 20: chi=t;break ; case 21: chi=u; break ; case 22: chi=v; break ; case 23: chi=w; break ; case 24: chi=x; break ; case 25: chi=y; break ; case 26: chi=z; break ; case 27:chi=0; break; case 28:chi=1; break; case 29:chi=2; break; case 30:chi=3; break; case 31:chi=4; break; case 32:chi=5; break; case 33:chi=6; break; case 34:chi=7; break; case 35:chi=8; break; case 36:chi=9; break;/end of switch cout chi; /end of for loopcout endl; delete ch; return 0; 而運行結(jié)果顯示的隨機字符串的每一個字符都是一樣的,也就是說生成的字符序列不隨機,所以我們需要把srand(unsigned)time(NULL); 從for循環(huán)中移出放在for語句前面,這樣可以生成隨機的字符序列,而且每次運行生成的字符序列會不同(呵呵,也有可能相同,不過出現(xiàn)這種情況的幾率太小了)。 如果你把srand(unsigned)time(NULL);改成srand(2);這樣雖然在一次運行中產(chǎn)生的字符序列是隨機的,但是每次運行時產(chǎn)生的隨機字符序列串是相同的。把srand這一句從程序中去掉也是這樣。 此外,你可能會遇到這種情況,在使用timer控件編制程序的時候會發(fā)現(xiàn)用相同的時間間隔生成的一組隨機數(shù)會顯得有規(guī)律,而由用戶按鍵command事件產(chǎn)生的一組隨機數(shù)卻顯得比較隨機,為什么?根據(jù)我們上面的分析,你可以很快想出答案。這是因為timer是由計算機時鐘記數(shù)器精確控制時間間隔的控件,時間間隔相同,記數(shù)器前后的值之差相同,這樣時鐘取值就是呈線性規(guī)律的,所以隨機種子是呈線性規(guī)律的,生成的隨機數(shù)也是有規(guī)律的。而用戶按鍵事件產(chǎn)生隨機數(shù)確實更呈現(xiàn)隨機性,因為事件是由人按鍵引起的,而人不能保證嚴(yán)格的按鍵時間間隔,即使嚴(yán)格地去做,也不可能完全精確做到,只要時間間隔相差一微秒,記數(shù)器前后的值之差就不相同了,隨機種子的變化就失去了線性規(guī)律,那么生成的隨機數(shù)就更沒有規(guī)律了,所以這樣生成的一組隨機數(shù)更隨機。這讓我想到了各種晚會的抽獎程序,如果用人來按鍵產(chǎn)生幸運觀眾的話,那就會很好的實現(xiàn)隨機性原則,結(jié)果就會更公正。 最后,我總結(jié)兩個要點: 1.計算機的偽隨機數(shù)是由隨機種子根據(jù)一定的計算方法計算出來的數(shù)值。所以,只要計算方法一定,隨機種子一定,那么產(chǎn)生的隨機數(shù)就是固定的。 2.只要用戶或第三方不設(shè)置隨機種子,那么在默認(rèn)情況下隨機種子來自系統(tǒng)時鐘- 1.請仔細(xì)閱讀文檔,確保文檔完整性,對于不預(yù)覽、不比對內(nèi)容而直接下載帶來的問題本站不予受理。
- 2.下載的文檔,不會出現(xiàn)我們的網(wǎng)址水印。
- 3、該文檔所得收入(下載+內(nèi)容+預(yù)覽)歸上傳者、原創(chuàng)作者;如果您是本文檔原作者,請點此認(rèn)領(lǐng)!既往收益都?xì)w您。
下載文檔到電腦,查找使用更方便
0 積分
下載 |
- 配套講稿:
如PPT文件的首頁顯示word圖標(biāo),表示該PPT已包含配套word講稿。雙擊word圖標(biāo)可打開word文檔。
- 特殊限制:
部分文檔作品中含有的國旗、國徽等圖片,僅作為作品整體效果示例展示,禁止商用。設(shè)計者僅對作品中獨創(chuàng)性部分享有著作權(quán)。
- 關(guān) 鍵 詞:
- C+ 隨機數(shù) 字符串 生成 源碼
鏈接地址:http://ioszen.com/p-6589664.html