-
當(dāng)前位置:首頁 > 創(chuàng)意學(xué)院 > 營銷推廣 > 專題列表 > 正文
偽隨機(jī)數(shù)生成器的要求
大家好!今天讓創(chuàng)意嶺的小編來大家介紹下關(guān)于偽隨機(jī)數(shù)生成器的要求的問題,以下是小編對此問題的歸納整理,讓我們一起來看看吧。
開始之前先推薦一個非常厲害的Ai人工智能工具,一鍵生成原創(chuàng)文章、方案、文案、工作計劃、工作報告、論文、代碼、作文、做題和對話答疑等等
只需要輸入關(guān)鍵詞,就能返回你想要的內(nèi)容,有小程序、在線網(wǎng)頁版、PC客戶端和批量生成器
問友Ai官網(wǎng):https://ai.de1919.com。
本文目錄:
什么是偽隨機(jī)數(shù)?
大家可能很多次討論過隨機(jī)數(shù)在計算機(jī)中怎樣產(chǎn)生的問題,在這篇文章中,我會對這個問題進(jìn)行更深入的探討,闡述我對這個問題的理解。首先需要聲明的是,計算機(jī)不會產(chǎn)生絕對隨機(jī)的隨機(jī)數(shù),計算機(jī)只能產(chǎn)生“偽隨機(jī)數(shù)”。其實絕對隨機(jī)的隨機(jī)數(shù)只是一種理想的隨機(jī)數(shù),即使計算機(jī)怎樣發(fā)展,它也不會產(chǎn)生一串絕對隨機(jī)的隨機(jī)數(shù)。計算機(jī)只能生成相對的隨機(jī)數(shù),即偽隨機(jī)數(shù)。
偽隨機(jī)數(shù)并不是假隨機(jī)數(shù),這里的“偽”是有規(guī)律的意思,就是計算機(jī)產(chǎn)生的偽隨機(jī)數(shù)既是隨機(jī)的又是有規(guī)律的。怎樣理解呢?產(chǎn)生的偽隨機(jī)數(shù)有時遵守一定的規(guī)律,有時不遵守任何規(guī)律;偽隨機(jī)數(shù)有一部分遵守一定的規(guī)律;另一部分不遵守任何規(guī)律。比如“世上沒有兩片形狀完全相同的樹葉”,這正是點到了事物的特性,即隨機(jī)性,但是每種樹的葉子都有近似的形狀,這正是事物的共性,即規(guī)律性。從這個角度講,你大概就會接受這樣的事實了:計算機(jī)只能產(chǎn)生偽隨機(jī)數(shù)而不能產(chǎn)生絕對隨機(jī)的隨機(jī)數(shù)。
那么計算機(jī)中隨機(jī)數(shù)是怎樣產(chǎn)生的呢?有人可能會說,隨機(jī)數(shù)是由“隨機(jī)種子”產(chǎn)生的。沒錯,隨機(jī)種子是用來產(chǎn)生隨機(jī)數(shù)的一個數(shù),在計算機(jī)中,這樣的一個“隨機(jī)種子”是一個無符號整形數(shù)。那么隨機(jī)種子是從哪里獲得的呢?
下面看這樣一個C程序:
//rand01.c
#include
static unsigned int RAND_SEED;
unsigned int random(void)
{
RAND_SEED=(RAND_SEED*123+59)%65536;
return(RAND_SEED);
}
void random_start(void)
{
int temp[2];
movedata(0x0040,0x006c,FP_SEG(temp),FP_OFF(temp),4);
RAND_SEED=temp[0];
}
main()
{
unsigned int i,n;
random_start();
for(i=0;i<10;i++)
printf("%u\t",random());
printf("\n");
}
這個程序(rand01.c)完整地闡述了隨機(jī)數(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ù)隨機(jī)種子RAND_SEED的值計算得出隨機(jī)數(shù),其中這一句:
RAND_SEED=(RAND_SEED*123+59)%65536;
是用來計算隨機(jī)數(shù)的方法,隨機(jī)數(shù)的計算方法在不同的計算機(jī)中是不同的,即使在相同的計算機(jī)中安裝的不同的操作系統(tǒng)中也是不同的。我在linux和windows下分別試過,相同的隨機(jī)種子在這兩種操作系統(tǒng)中生成的隨機(jī)數(shù)是不同的,這說明它們的計算方法不同。
現(xiàn)在,我們明白隨機(jī)種子是從哪兒獲得的,而且知道隨機(jī)數(shù)是怎樣通過隨機(jī)種子計算出來的了。那么,隨機(jī)種子為什么要在內(nèi)存的0040:006CH處?。?040:006CH處存放的是什么?
學(xué)過《計算機(jī)組成原理與接口技術(shù)》這門課的人可能會記得在編制ROM BIOS時鐘中斷服務(wù)程序時會用到Intel 8253定時/計數(shù)器,它與Intel 8259中斷芯片的通信使得中斷服務(wù)程序得以運(yùn)轉(zhuǎn),主板每秒產(chǎn)生的18.2次中斷正是處理器根據(jù)定時/記數(shù)器值控制中斷芯片產(chǎn)生的。在我們計算機(jī)的主機(jī)板上都會有這樣一個定時/記數(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,從而獲得了“隨機(jī)種子”。
現(xiàn)在,可以確定的一點是,隨機(jī)種子來自系統(tǒng)時鐘,確切地說,是來自計算機(jī)主板上的定時/計數(shù)器在內(nèi)存中的記數(shù)值。這樣,我們總結(jié)一下前面的分析,并討論一下這些結(jié)論在程序中的應(yīng)用:
1.隨機(jī)數(shù)是由隨機(jī)種子根據(jù)一定的計算方法計算出來的數(shù)值。所以,只要計算方法一定,隨機(jī)種子一定,那么產(chǎn)生的隨機(jī)數(shù)就不會變。
看下面這個C++程序:
//rand02.cpp
#include
#include
using namespace std;
int main()
{
unsigned int seed=5;
srand(seed);
unsigned int r=rand();
cout< // 編輯者注:可能代碼有缺
}
在相同的平臺環(huán)境下,編譯生成exe后,每次運(yùn)行它,顯示的隨機(jī)數(shù)都是一樣的。這是因為在相同的編譯平臺環(huán)境下,由隨機(jī)種子生成隨機(jī)數(shù)的計算方法都是一樣的,再加上隨機(jī)種子一樣,所以產(chǎn)生的隨機(jī)數(shù)就是一樣的。
2.只要用戶或第三方不設(shè)置隨機(jī)種子,那么在默認(rèn)情況下隨機(jī)種子來自系統(tǒng)時鐘(即定時/計數(shù)器的值)
看下面這個C++程序:
//rand03.cpp
#include
#include
using namespace std;
int main()
{
srand((unsigned)time(NULL));
unsigned int r=rand();
cout< return 0;
}
這里用戶和其他程序沒有設(shè)定隨機(jī)種子,則使用系統(tǒng)定時/計數(shù)器的值做為隨機(jī)種子,所以,在相同的平臺環(huán)境下,編譯生成exe后,每次運(yùn)行它,顯示的隨機(jī)數(shù)會是偽隨機(jī)數(shù),即每次運(yùn)行顯示的結(jié)果會有不同。
3.建議:如果想在一個程序中生成隨機(jī)數(shù)序列,需要至多在生成隨機(jī)數(shù)之前設(shè)置一次隨機(jī)種子。
看下面這個用來生成一個隨機(jī)字符串的C++程序:
//rand04.cpp
#include
#include
using namespace std;
int main()
{
int rNum,m=20;
char *ch=new char[m];
for ( int i = 0; i //大家看到了,隨機(jī)種子會隨著for循環(huán)在程序中設(shè)置多次
srand((unsigned)time(NULL));
rNum=1+(int)((rand()/(double)RAND_MAX)*36); //求隨機(jī)值
switch (rNum){
case 1: ch[i]='a';
break ;
case 2: ch[i]='b';
break ;
case 3: ch[i]='c';
break ;
case 4: ch[i]='d';
break ;
case 5: ch[i]='e';
break ;
case 6: ch[i]='f';
break ;
case 7: ch[i]='g';
break ;
case 8: ch[i]='h';
break ;
case 9: ch[i]='i';
break ;
case 10: ch[i]='j';
break ;
case 11: ch[i]='k';
break ;
case 12: ch[i]='l';
break ;
case 13: ch[i]='m';
break ;
case 14: ch[i]='n';
break ;
case 15: ch[i]='o';
break ;
case 16: ch[i]='p';
break ;
case 17: ch[i]='q';
break ;
case 18: ch[i]='r';
break ;
case 19: ch[i]='s';
break ;
case 20: ch[i]='t';
break ;
case 21: ch[i]='u';
break ;
case 22: ch[i]='v';
break ;
case 23: ch[i]='w';
break ;
case 24: ch[i]='x';
break ;
case 25: ch[i]='y';
break ;
case 26: ch[i]='z';
break ;
case 27:ch[i]='0';
break;
case 28:ch[i]='1';
break;
case 29:ch[i]='2';
break;
case 30:ch[i]='3';
break;
case 31:ch[i]='4';
break;
case 32:ch[i]='5';
break;
case 33:ch[i]='6';
break;
case 34:ch[i]='7';
break;
case 35:ch[i]='8';
break;
case 36:ch[i]='9';
break;
}//end of switch
cout< }//end of for loop
cout< return 0;
}
而運(yùn)行結(jié)果顯示的隨機(jī)字符串的每一個字符都是一樣的,也就是說生成的字符序列不隨機(jī),所以我們需要把srand((unsigned)time(NULL)); 從for循環(huán)中移出放在for語句前面,這樣可以生成隨機(jī)的字符序列,而且每次運(yùn)行生成的字符序列會不同(呵呵,也有可能相同,不過出現(xiàn)這種情況的幾率太小了)。
如果你把srand((unsigned)time(NULL));改成srand(2);這樣雖然在一次運(yùn)行中產(chǎn)生的字符序列是隨機(jī)的,但是每次運(yùn)行時產(chǎn)生的隨機(jī)字符序列串是相同的。把srand這一句從程序中去掉也是這樣。
此外,你可能會遇到這種情況,在使用timer控件編制程序的時候會發(fā)現(xiàn)用相同的時間間隔生成的一組隨機(jī)數(shù)會顯得有規(guī)律,而由用戶按鍵command事件產(chǎn)生的一組隨機(jī)數(shù)卻顯得比較隨機(jī),為什么?根據(jù)我們上面的分析,你可以很快想出答案。這是因為timer是由計算機(jī)時鐘記數(shù)器精確控制時間間隔的控件,時間間隔相同,記數(shù)器前后的值之差相同,這樣時鐘取值就是呈線性規(guī)律的,所以隨機(jī)種子是呈線性規(guī)律的,生成的隨機(jī)數(shù)也是有規(guī)律的。而用戶按鍵事件產(chǎn)生隨機(jī)數(shù)確實更呈現(xiàn)隨機(jī)性,因為事件是由人按鍵引起的,而人不能保證嚴(yán)格的按鍵時間間隔,即使嚴(yán)格地去做,也不可能完全精確做到,只要時間間隔相差一微秒,記數(shù)器前后的值之差就不相同了,隨機(jī)種子的變化就失去了線性規(guī)律,那么生成的隨機(jī)數(shù)就更沒有規(guī)律了,所以這樣生成的一組隨機(jī)數(shù)更隨機(jī)。這讓我想到了各種晚會的抽獎程序,如果用人來按鍵產(chǎn)生幸運(yùn)觀眾的話,那就會很好的實現(xiàn)隨機(jī)性原則,結(jié)果就會更公正。
最后,我總結(jié)兩個要點:
1.計算機(jī)的偽隨機(jī)數(shù)是由隨機(jī)種子根據(jù)一定的計算方法計算出來的數(shù)值。所以,只要計算方法一定,隨機(jī)種子一定,那么產(chǎn)生的隨機(jī)數(shù)就是固定的。
2.只要用戶或第三方不設(shè)置隨機(jī)種子,那么在默認(rèn)情況下隨機(jī)種子來自系統(tǒng)時鐘。
偽隨機(jī)數(shù)的生成方法
一般地,偽隨機(jī)數(shù)的生成方法主要有以下3種:
(1) 直接法(Direct Method),根據(jù)分布函數(shù)的物理意義生成。缺點是僅適用于某些具有特殊分布的隨機(jī)數(shù),如二項式分布、泊松分布。
(2) 逆轉(zhuǎn)法(Inversion Method),假設(shè)U服從[0,1]區(qū)間上的均勻分布,令X=F-1(U),則X的累計分布函數(shù)(CDF)為F。該方法原理簡單、編程方便、適用性廣。
(3)接受拒絕法(Acceptance-Rejection Method):假設(shè)希望生成的隨機(jī)數(shù)的概率密度函數(shù)(PDF)為f,則首先找到一個PDF為g的隨機(jī)數(shù)發(fā)生器與常數(shù)c,使得f(x)≤cg(x),然后根據(jù)接收拒絕算法求解。由于算法平均運(yùn)算c次才能得到一個希望生成的隨機(jī)數(shù),因此c的取值必須盡可能小。顯然,該算法的缺點是較難確定g與c。
因此,偽隨機(jī)數(shù)生成器(PRNG)一般采用逆轉(zhuǎn)法,其基礎(chǔ)是均勻分布,均勻分布PRNG的優(yōu)劣決定了整個隨機(jī)數(shù)體系的優(yōu)劣[7]。下文研究均勻分布的PRNG。
以上就是關(guān)于偽隨機(jī)數(shù)生成器的要求相關(guān)問題的回答。希望能幫到你,如有更多相關(guān)問題,您也可以聯(lián)系我們的客服進(jìn)行咨詢,客服也會為您講解更多精彩的知識和內(nèi)容。
推薦閱讀:
機(jī)關(guān)公文規(guī)范重要性(機(jī)關(guān)公文規(guī)范重要性分析)
國內(nèi)外著名的餐飲品牌設(shè)計(國內(nèi)外著名的餐飲品牌設(shè)計師)