等概率隨機函數的實現


利用等概率函數Rand5產生等概率函數Rand3

問題描述:現在有一個叫做Rand5的函數,可以生成等概率的[0, 5)范圍內的隨機整數,要求利用此函數寫一個Rand3函數(除此之外,不能再使用任何能產生隨機數的函數或數據源),生成等概率的[0, 3)范圍內的隨機整數。

//使用Rand5()實現Rand3()   
int Rand3()  
{  
    int x;  
    do  
    {  
        x = Rand5();  
    } while (x >= 3);  
    return x;  
}  
  
//利用Rand3編寫Rand5怎么辦?   
int Rand5()  
{  
    int x;  
    do  
    {  
        x = Rand3() * 3 + Rand3();  
    } while (x >= 5);  
    return x;  
}   
  
//如果要求利用Rand5編寫Rand7怎么辦?   
int Rand7()  
{  
    int x;  
    do  
    {  
        x = Rand5() * 5 + Rand5();  
    } while (x >= 21);  
    return x % 7;  
}   

數學證明詳情:http://www.gocalf.com/blog/build-rank3-from-rand5.html

題目:已知有個rand7()的函數,可以生成等概率的[1,7]范圍內的隨機整數,讓利用這個rand7()構造rand10()函數,生成等概率的[1,10]范圍內的隨機整數。

分析:要保證rand10()在整數1-10的均勻分布,可以構造一個1-10*n的均勻分布的隨機整數區間(n為任何正整數)。假設x是這個1-10*n區間上的一個隨機整數,那么x%10+1就是均勻分布在1-10區間上的整數。由於(rand7()-1)*7+rand7()可以構造出均勻分布在1-49的隨機數(原因見下面的說明),可以將41~49這樣的隨機數剔除掉,得到的數1-40仍然是均勻分布在1-40的,這是因為每個數都可以看成一個獨立事件。

下面說明為什么(rand7()-1)*7+rand7()可以構造出均勻分布在1-49的隨機數:
首先rand7()-1得到一個離散整數集合{0,1,2,3,4,5,6},其中每個整數的出現概率都是1/7。那么(rand7()-1)*7得到一個離散整數集合A={0,7,14,21,28,35,42},其中每個整數的出現概率也都是1/7。而rand7()得到的集合B={1,2,3,4,5,6,7}中每個整數出現的概率也是1/7。顯然集合A和B中任何兩個元素組合可以與1-49之間的一個整數一一對應,也就是說1-49之間的任何一個數,可以唯一確定A和B中兩個元素的一種組合方式,反過來也成立。由於A和B中元素可以看成是獨立事件,根據獨立事件的概率公式P(AB)=P(A)P(B),得到每個組合的概率是1/7*1/7=1/49。因此(rand7()-1)*7+rand7()生成的整數均勻分布在1-49之間,每個數的概率都是1/49。

int rand_10()    
{    
    int x = 0;    
    do    
    {    
        x = 7 * (rand7() - 1) + rand7();    
    }while(x > 40);    
    return x % 10 + 1;    
}   

注:為什么用while(x>40)而不用while(x>10)呢?原因是如果用while(x>10)則有40/49的概率需要循環while,很有可能死循環了。

歸納總結:將這個問題進一步抽象,已知random_m()隨機數生成器的范圍是[1, m] 求random_n()生成[1, n]范圍的函數,m < n && n <= m *m

int random_n()    
{    
    int val = 0;    
    int t;   //t為n的最大倍數,且滿足t<m*m      
    do    
    {    
        val = m * (random_m() - 1) + random_m();    
    }while(val > t);    
    return val % n + 1;    
}  

題目:已知隨機函數rand(),以p的概率產生0,以1-p的概率產生1,現在要求設計一個新的隨機函數newRand(),使其以1/n的等概率產生1~n之間的任意一個數。

解決思路:可以通過已知隨機函數rand()產生等概率產生0和1的新隨機函數Rand(),然后調用k(k為整數n的二進制表示的位數)次Rand()函數,得到一個長度為k的0和1序列,以此序列所形成的整數即為1--n之間的數字。注意:從產生序列得到的整數有可能大於n,如果大於n的話,則重新產生直至得到的整數不大於n。
第一步:由rand()函數產生Rand()函數,Rand()函數等概率產生0和1
第二步:計算整數n的二進制表示所擁有的位數k,k = 1 +log2n(log以2為底n)
第三步:調用k次Rand()產生隨機數,產生的k個01序列表示1-n之間的數

int Rand()    
{    
    int i1 = rand();    
    int i2 = rand();    
    if(i1==0 && i2==1)    
        return 1;    
    else if(i1==1 && i2==0)    
        return 0;    
    else    
        return Rand();    
    return -1;    
}  
int newRand()    
{    
    int result = 0;    
    for(int i = 0 ; i < k ; ++i)    
    {    
        if(Rand() == 1)    
            result |= (1<<i);    
    }    
    if(result > n)    
        return newRand();    
    return result;    
}  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM