詳解C說話的隨機數生成及其相干標題。本站提示廣大學習愛好者:(詳解C說話的隨機數生成及其相干標題)文章只能為提供參考,不一定能成為您想要的結果。以下是詳解C說話的隨機數生成及其相干標題正文
發生隨機數的根本辦法
本文中,筆者將引見c說話所供給的隨機數產生器的用法。如今的c編譯法式都供給了一個基於一種ANSI尺度的偽隨機數產生器函數,用來生成隨機數。Microsoft和Borland都是經由過程rand()和srand()函數來支撐這類尺度的,它們的任務進程以下:
起首,給srand()供給一個“種子”,它是一個unsignde int類型,其取值規模是從0到65,535 ;
然後,挪用rand(),它會依據供給給srand()的“種子”值前往一個隨機數(在0到32,767之間);
依據須要屢次挪用rand(),從而赓續地獲得新的隨機數;
不管甚麼時刻,你都可以給srand()供給一個新的“種子”,從而進一步“隨機化"rand()的輸入成果。
這個進程看起來很簡略,成績是假如你每次挪用srand()時都供給雷同的“種子”值,那末你將會獲得雷同的“隨機”數序列。例如,在以17為“種子”值挪用srand()以後,在你初次挪用rand()時,你將獲得隨機數94;在你第二次和第三次挪用rand()時,你將分離獲得26,602和30,017。這些數看上去是相當隨機的(雖然這只是一個很小的數據點聚集),然則,在你再次以17為“種子”值挪用srand()以後,在對rand()的前三次挪用中,所獲得的前往值依然是94、26,602和30,017,而且爾後獲得的前往值依然是在對rand()的第一批挪用中所獲得的其他的前往值。是以,只要再次給srand()供給一個隨機的“種子”值,能力再次獲得一個隨機數。
上面的例子用一種簡略而有用的方法來發生一個相當隨機的“種子”值——當天的時光值。
# include <stdlib. h> # include <stdio. h> # include <sys/types. h> # include <sys/timeb. h> void main (void){ int i ; unsigned int seedVal; struct_timeb timeBuf ; _ftime (&timeBuf) ; seedVal = ( ( ( ( (unsigned int)timeBuf, time & 0xFFFF) + (unsigned int)timeBuf, millitm) ^ (unsigned int)timeBuf, millitm) ; srand ((unsigned int)seedVal) ; for(i=O;i<lO;++i) printf (" %6d\n" ,rand ( ) ) ; }
上例先是挪用_ftime()來檢索以後時光,並把它的值存入構造成員timeBuf.time中,以後時光的值從1970年1月1日開端以秒盤算。在挪用了_ftime()以後,在構造timeBuf的成員millitm中還存入了在以後那一秒曾經渡過的毫秒數,但在DOS中這個數字現實上是以百分之一秒來盤算的。然後,把毫秒數和秒數相加,再和毫秒數停止一次異或運算。你可以對這兩個構造成員施加更多的邏輯運算,以掌握seedVal的取值規模,並進一步增強它的隨機性,但上例所用的邏輯運算曾經足夠了。
留意,在後面的例子中,rand()的輸入並沒有被限制在一個指定的規模內,假定你想樹立一個彩票選號器,其取值規模是從1到44。你可以簡略地疏忽失落rand()所輸入的在該規模以外的值,但這將消費很多時光去獲得所需的全體(例如6個)彩票號碼。假定你曾經樹立了一個令你滿足的隨機數產生器,它所發生的隨機數據規模是從0到32,767(就象前文中提到過的那樣),而你想把輸入限制在1到44之間,上面的例子就解釋了若何來完成這項任務:
int i ,k ,range ; int rain, max ; double j ; min=1; /* 1 is the minimum number allowed */ max=44; /* 44 is the maximum number allowed */ range=max-min; /* r is the range allowed; 1 to 44 */ i=rand(); /* use the above example in this slot */ /* Normalize the rand() output (scale to 0 to 1) */ /* RAND_MAX is defined in stdlib, h */ j= ((double)i/(double)RAND_MAX) ; /* Scale the output to 1 to 44 */ i= (int)(j * (double)range) ; i+ =min;
上例把輸入的隨機數限制在1到44之間,其任務道理以下:
獲得一個在O到RAND_MAX(32,767)之間的隨機數,把它除以RAND_MAX,從而發生一個在0到1之間的校訂值;
把校訂值乘以所須要的規模值(在本例中為43,即44減去1),從而發生一個在O到43之間的值;
把該值和所請求的最小值相加,從而使該值終究落在准確的取值規模——1到44以內。
你可以用分歧的min和max值來驗證這個例子,你會發明它老是會准確地發生在新的rain和max值之間的隨機數。
上面來看一下隨機數的相干演習標題
標題
給定了rand7,若何生成rand3?
思緒
一個異常直不雅的思緒,就是赓續的挪用rand7,直到它發生1-3之間的數,然後前往。代碼以下:(假如有同窗說這裡沒有3,然則不代表我不克不及斷定和3的年夜小比擬吧)
#include <stdio.h> int rand_3() { int x; while (x = rand_7()) { if (x <= 3) { return x; } } }
接上去,就是斷定rand_3能否能等幾率的發生1,2,3.也就是我們須要盤算發生1,2,3的幾率能否都是1/3.
起首,rand_7可以等幾率的發生1-7,我們以rand_3生成1為例,假定:
是以,rand_3生成1的幾率是P(x=1)= 1/7 + (4/7) * 1/7 + (4/7)^2 * 1/7 + ... + (4/7)^n-1 * 1/7 //等比數列
= 1/7 * ((1 - (4/7)^n) / 1 - 4/7) = 1/7 * 7/3 = 1/3
同理,可驗證生成2,3的幾率均為1/3
結論
上述證實解釋rand3可以等幾率的發生1,2,3.從下面的剖析,我們可以得出一個更普通的結論:
假如a>b,我們必定可以用rand_a去完成rand_b.個中,rand_a是等能夠的生成1-a,rand_b是等能夠的生成1-b
擴大
如今給定兩個生成隨機數的函數rand_a和rand_b,rand_a和rand_b分離發生1-a和1-b的隨機數,a和b不相等,如今讓你用rand_a完成rand_b,辦法以下:
舉例解釋
阿裡2014年口試標題,是給定生成1-7的隨即函數rand_7,看能否能生成其它隨機數?
我們先看一下能否能等幾率生成1-49,結構rand_49 = 7 * (rand_7 - 1) + rand_7 (ps:別問我7從哪裡來的,rand_7既然能隨即生成1-7,我固然可以取得到7了)
rand_7 - 1能等幾率的生成0, 1, 2, 3, 4, 5, 6,每一個數的生成幾率都是1/7,所以*7以後,可以等幾率的生成0,7,14,21,28,35,42,每一個數的幾率都是1/7
既然0,7,14,21,28,35,42每一個數的幾率都是1/7,當每一個數都加上+rand_7以後,則1-49是等幾率發生的,1/7 × 1/7 = 1/49,中央不會湧現反復數據
所以,我們用rand_7發生了rand_49,有了rand_49,依照最後下面過濾的辦法,我們固然可以取得任何小於49的隨機函數