C/C++產生隨機數



轉載自 江南煙雨夢 的文章

原文地址: http://blog.csdn.net/beyond0824/article/details/6009908


C/C++怎樣產生隨機數:這裏要用到的是rand()函數, srand()函數,C語言/C++裏沒有自帶的random(int number)函數。
(1)  如果你只要產生隨機數而不需要設定範圍的話,你只要用rand()就可以了:rand()會返回一隨機數值, 範圍在0至RAND_MAX 間。RAND_MAX定義在stdlib.h, 其值爲2147483647。
例如:

#include<stdio.h>
#include<stdlib.h>
void main()
{
       for(int i=0;i<10;i+)
             printf("%d/n",rand());
}

(2)  如果你要隨機生成一個在一定範圍的數,你可以在宏定義中定義一個random(int number)函數,然後在main()裏面直接調用random()函數:

例如:隨機生成10個0~100的數:
#include<stdio.h>
#include<stdlib.h>
#define random(x) (rand()%x)

void main()
{
     for(int x=0;x<10;x++)
           printf("%d/n",random(100));
}

 

(3)但是上面兩個例子所生成的隨機數都只能是一次性的,如果你第二次運行的時候輸出結果仍和第一次一樣。這與srand()函數有關。srand()用來設置rand()產生隨機數時的隨機數種子。在調用rand()函數產生隨機數前,必須先利用srand()設好隨機數種子(seed), 如果未設隨機數種子, rand()在調用時會自動設隨機數種子爲1。上面的兩個例子就是因爲沒有設置隨機數種子,每次隨機數種子都自動設成相同值1 ,進而導致rand()所產生的隨機數值都一樣。

srand()函數定義 : void srand (unsigned int seed);
通常可以利用geypid()或time(0)的返回值來當做seed
如果你用time(0)的話,要加入頭文件#include<time.h>

例如:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define random(x) (rand()%x)

void main()
{

     srand((int)time(0));
     for(int x=0;x<10;x++)
           printf("%d/n",random(100));
}

這樣兩次運行的結果就會不一樣了!!

 

<二>

標準C庫中函數rand()可以生成0~RAND_MAX之間的一個隨機數,其中RAND_MAX 是stdlib.h 中定義的一個整數,它與系統有關。

rand()函數沒有輸入參數,直接通過表達式rand()來引用;例如可以用下面的語句來打印兩個隨機數:

printf("Random numbers are: %i %i/n",rand(),rand());

因爲rand()函數是按指定的順序來產生整數,因此每次執行上面的語句都打印相同的兩個值,所以說C語言的隨即並不是正真意義上的隨機。

爲了時程序在每次執行時都能生成一個新序列的隨機值,我們通常通過爲隨機數生成器提供一粒新的隨機種子。函數srand()(來自stdlib.h)可以爲隨機數生成器播散種子。只要種子不同rand()函數就會產生不同的隨機數序列。srand()稱爲隨機數生成器的初始化器。

例程:

文件名: rand_srand.c

/* This program generates and prints ten random integers between 1 and RAND_MAX*/

#include <stdio.h>

#includ <stdlib.h>

int main()

{

        usigned int seed;        /*申明初始化器的種子,注意時usigned int 型的*/

        int k;

        pringt("Enter a positive integer seed value: /n");

        scanf("%u",&seed);

        srand(seed);

        printf("Random Numbers are:/n");

        for(k = 1; k <= 10; k++)

        printf("%i",rand());

        printf("/n");

        return 0;

}

你會發現,當你提供的種子相同時,隨機數序列也時相同的。而且當種子爲1時,與不使用srand()函數時一樣的,也就是說rand()函數默認情況下初始化種子值爲1;

在stdlib.h 中這兩個函數的原型是:

int rand();

void srand (unsigned int);

擴充:

        x = rand()%11; /*產生1~10之間的隨機整數*/

        y = rand()%51 - 25; /*產生-25 ~ 25之間的隨機整數*/

        z = ((double)rand()/RAND_MAX)*(b-a) + a;/*產生區間[a,b]上的隨機數*/

 

<三>

 

1-0:Microsoft VC++產生隨機數的原理:

Srand ( )和Rand( )函數。它本質上是利用線性同餘法,y=ax+b(mod m)。其中a,b,m都是常數。因此rand的產生決定於x,x被稱爲Seed。Seed需要程序中設定,一般情況下取系統時間作爲種子。它產生的隨機數之間的相關性很小,取值範圍是0—32767(int),即雙字節(16位數),若用unsigned int 雙字節是65535,四字節是4294967295,一般可以滿足要求。

1-1: 線性同餘法:

?/P>

其中M是模數,A是乘數,C是增量,爲初始值,當C=0時,稱此算法爲乘同餘法;若C≠0,則稱算法爲混合同餘法,當C取不爲零的適當數值時,有一些優點,但優點並不突出,故常取C=0。模M大小是發生器週期長短的主要標誌,常見有M爲素數,取A爲M的原根,則週期T=M-1。例如:

a=1220703125        

a=32719            (程序中用此組數)   

     a=16807          

代碼:

void main( )

{

const int n=100;

double a=32719,m=1,f[n+1],g[n],seed;

m=pow(2,31);

cout<<"設置m值爲  "<<m-1<<endl;

cout<<"輸入種子"<<endl;  //輸入種子

cin>>seed;

f[0]=seed;    

    for(int i=1;i<=n;i++)    //線性同餘法生成隨機數

      {

         f[i]=fmod((a*f[i-1]),(m-1));

             g[i-1]=f[i]/(m-1);

             cout.setf(ios::fixed);cout.precision(6); //設置輸出精度

         cout<<i<<"   "<<"/n"<<g[i-1]<<endl;

      }

}

結果分析:統計數據的平均值爲:0.485653

統計數據的方差爲:0.320576

 

1-2:人字映射

遞推公式

?/P>

就是有名的混沌映射中的“人字映射”或稱“帳篷映射”,它的非週期軌道點的分佈密度函數:人字映射與線性同餘法結合,可產生統計性質優良的均勻隨機數。

 for(int i=1;i<=n;i++)    //線性同餘法生成隨機數

      {

         f[i]=fmod((a*f[i-1]),m);

             if(f[i]<=m/2)     //與人字映射結合生成隨機數

             {

                    f[i]=2*f[i];

             }

             else

             {

                    f[i]=2*(m-f[i])+1;

             }

1-3:平方取中法——馮·諾伊曼

1946年前後,由馮·諾伊曼提出,他的辦法是去前面的隨機數的平方,並抽取中部的數字。例如要生成10位數字,而且先前的值是5772156649,平方後得到33317792380594909201,所以下一個數是7923805949。

for(j=1;j<=n;j++)

      {

             i[j]=i[j-1]*i[j-1];  

        i[j]=i[j]/pow(10,5); 

        i[j]=fmod(i[j],pow(10,10));

        g[j]=i[j]/pow(10,10);

        cout.setf(ios::fixed);cout.precision(6); //設置輸出精度

        cout<<j<<'/t'<<g[j]<<endl;

      }

二:任意分佈隨機數的生成

     利用(0,1)均勻分佈的隨機數可以產生任意分佈的隨機數。主要的方法有反函數法,舍選法,離散逼近法,極限近似法和隨機變量函數法等。這裏主要討論了反函數法,當然對於具體分佈函數可以採用不同的方法。

設隨機變量X具有分佈函數F(X),則對一個給定的分佈函數值,X的值爲
                                              

其中inv表示反函數。現假設r是(0,1)均勻分佈的隨機變量R的一個值,已知R的分佈函數爲

                              

因此,如果r是R的一個值,則X具有概率

 

也就是說如果 (r1,r2,...,rn)是R的一組值,則相應可得到的一組值

                    

具有分佈。從而,如果我們已知分佈函數的反函數,我們就可以從(0,1)分佈的均勻分佈隨機數得到所需分佈的隨機數了。

1-4:指數分佈:

指數分佈的分佈函數爲:

x<0時,F(x)=0    ; ,F(x)=1-exp

利用上面所述反函數法,可以求得:  x= ln(1-y),這裏不妨取常數 爲1.

for(int j=0;j<n;j++)

       { 

              i=rand()%100;//產生從0-32767的任意一個值

        a[j]=double(i)/double(100); 

          a[j]=-log(a[j]);//  常數大於0,這裏取1

          、、、、、、、

1-5:正態分佈:

正態分佈的概率密度是:

正態分佈的分佈函數是:

對於正態分佈,利用反函數的方法來獲取正態分佈序列顯然是很麻煩的,牽涉到很複雜的積分微分運算,同時爲了方便,我們取,即標準正態分佈。因此這裏介紹了兩種算法:

第一種:

Box和Muller在1958年給出了由均勻分佈的隨機變量生成正態分佈的隨機變量的算法。設U1, U2是區間 (0, 1)上均勻分佈的隨機變量,且相互獨立。令  

  X1=sqrt(-2*log(U1)) * cos(2*PI*U2); 

  X2=sqrt(-2*log(U1)) * sin(2*PI*U2);  

那麼X1, X2服從N(0,1)分佈,且相互獨立。

             p=rand()%100;//產生從0-32767的任意一個值

             b[j]=double(p)/double(100);

             a[j]=sqrt(-2*log(a[j]))*cos(2*3.1415926*b[j]);

第二種:

近似生成標準正態分佈,獨立同分布的多個隨機變量和的分佈趨近於正態分佈,取k個均勻分佈的(0,1)隨機變量,,…… ,則它們的和近似服從正態分佈。

  實踐中,取k=12,(因爲D( )=1/12),則新的隨機變量y=x1+x2+...+x12-6,可以求出數學期望E(y)=0,方差D(y)=12*1/12=1,因此可以近似描述標準正態分佈。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章