題目:已知隨機函數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。
- 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 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;
}
第二步:計算整數n的二進制表示所擁有的位數k,k = 1 +log2n(log以2爲底n)第三步:調用k次Rand()產生隨機數。
- 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;
- }
int newRand()
{
int result = 0;
for(int i = 0 ; i < k ; ++i)
{
if(Rand() == 1)
result |= (1<<i); //每次出現0,1的概率是相等的,那麼通過該表達式讓前k位中每位出現0或者1的概率一樣
}
if(result > n)
return newRand();
return result;
}
題目:
給定一個函數rand5(),該函數可以隨機生成1-5的整數,且生成概率一樣。現要求使用該函數構造函數rand7(),使函數rand7()可以隨機等概率的生成1-7的整數。
思路:
很多人的第一反應是利用rand5() + rand()%3來實現rand7()函數,這個方法確實可以產生1-7之間的隨機數,但是仔細想想可以發現數字生成的概率是不相等的。rand()%3 產生0的概率是1/5,而產生1和2的概率都是2/5,所以這個方法產生6和7的概率大於產生5的概率。
正確的方法是利用rand5()函數生成1-25之間的數字,然後將其中的1-21映射成1-7,丟棄22-25。例如生成(1,1),(1,2),(1,3),則看成rand7()中的1,如果出現剩下的4種,則丟棄重新生成。
簡單實現:
- int rand7()
- {
- int x = 0;
- do
- {
- x = 5 * (rand5() - 1) + rand5();
- }while(x > 21);
- return 1 + x%7;
- }
int rand7()
{
int x = 0;
do
{
x = 5 * (rand5() - 1) + rand5();
}while(x > 21);
return 1 + x%7;
}
我的備註:這種思想是基於,rand()產生[0,N-1],把rand()視爲N進制的一位數產生器,那麼可以使用rand()*N+rand()來產生2位的N進制數,以此類推,可以產生3位,4位,5位...的N進制數。這種按構造N進制數的方式生成的隨機數,必定能保證隨機,而相反,藉助其他方式來使用rand()產生隨機數(如 rand5() + rand()%3 )都是不能保證概率平均的。
此題中N爲5,因此可以使用rand5()*5+rand5()來產生2位的5進制數,範圍就是1到25。再去掉22-25,剩餘的除3,以此作爲rand7()的產生器。
給定一個函數rand()能產生0到n-1之間的等概率隨機數,問如何產生0到m-1之間等概率的隨機數?
- int random(int m , int n)
- {
- int k = rand();
- int max = n-1;
- while(k < m)
- {
- k = k*n + rand();
- max = max*n + n-1;
- }
- return k/(max/n);
- }
int random(int m , int n)
{
int k = rand();
int max = n-1;
while(k < m)
{
k = k*n + rand();
max = max*n + n-1;
}
return k/(max/n);
}
如何產生如下概率的隨機數?0出1次,1出現2次,2出現3次,n-1出現n次?
- int random(int size)
- {
- while(true)
- {
- int m = rand(size);
- int n = rand(size);
- if(m + n < size)
- return m+n;
- }
- }