在上一篇文章(http://blog.csdn.net/xzjxylophone/article/details/6835332)中,我們主要完成了這個C#工程的重構和Rand10,Rand12的另一種實現。
這次我們來實現如果用Rand7來產生一個Rand11.
按照以前的思路計算Rand10的時候是分成2個集合(1,3,5,7,9)(2,4,6,810)
那麼我們是否可以把11也分成2個集合(1,3,5,7,9,11)和(2,4,6,8,10);
按照10的思路,在Rand10.Next()函數中應該把代碼:
if (n > 4)
num *= 2;
else
num = num * 2 - 1;
在Rand11.Next()修改成:
if (n > 4)
num = 2*num-1;//1,3,5,7,9,11
else
num = 2 * Rand5;//此處的Rand5表示隨即產生一個1-5的一個數
爲了完成Rand11,那必須先實現Rand5.
Rand5
public class Rand5 : Rand7Base
{
private Rand5()
{
_maxNum = 5;
}
public static Rand5 GetInstance()
{
if (rand == null || !(rand is Rand5))
{
rand = new Rand5();
}
return (Rand5)rand;
}
//獲得隨機數
override public int Next()
{
int num;
//均勻產生1、 2 、3、4、5
while (true)
{
num = _rand7.Next();
if (num <= 5)
return num;
}
}
}
按照前述的思路完成Rand11:
public class Rand11 : Rand7Base
{
private Rand11()
{
_maxNum = 11;
}
public static Rand11 GetInstance()
{
if (rand == null || !(rand is Rand11))
{
rand = new Rand11();
}
return (Rand11)rand;
}
//獲得隨機數
override public int Next()
{
int num;
label:
while (true) //代碼塊1
{
num = _rand7.Next();
if (num <= 6)
break;
}
//1<=num<=6
//1.3.5.7.9.11 num*2-1
//2.4.6.8.10 num*2
while (true)
{
int n = _rand7.Next();
if (n == 1)
continue;
if (n > 4)
num = num * 2 - 1; // 代碼塊2
else
{
num = 2 * Rand5.GetInstance().Next();//隨即獲取1-5,保證num爲(2,4,6,8,10) //代碼塊3
}
break;
}
return num;
}
}
添加測試函數:
static void TestRand5()
{
Rand5 rand = Rand5.GetInstance();
TestRand(rand);
}
static void TestRand11()
{
Rand11 rand = Rand11.GetInstance();
TestRand(rand);
}
測試Rand5和Rand11得到的測試結果:
計算Rand5的概率如下
產生1的概率是:0.1998812
產生2的概率是:0.2001405
產生3的概率是:0.1998788
產生4的概率是:0.2001452
產生5的概率是:0.1999543
耗時: 1.35574716655683 秒
Average:0.2000000;Max:0.2001452;Min:0.1998788
Max:0.2001452, Max-Average:0.0001452, Bits:0.0726000%
Min:0.1998788, Min-Average:-0.0001212, Bits:-0.0606000%
計算Rand11的概率如下
產生1的概率是:0.0833986
產生2的概率是:0.0998455
產生3的概率是:0.0832477
產生4的概率是:0.1000255
產生5的概率是:0.0832922
產生6的概率是:0.1000058
產生7的概率是:0.0833212
產生8的概率是:0.0999634
產生9的概率是:0.0834429
產生10的概率是:0.1001360
產生11的概率是:0.0833212
耗時: 2.95999916630916 秒
Average:0.0909091;Max:0.1001360;Min:0.0832477
Max:0.1001360, Max-Average:0.0092269, Bits:10.1496000%
Min:0.0832477, Min-Average:-0.0076614, Bits:-8.4275300%
Rand5是正確的。Rand11的誤差範圍居然在-8%----10%這裏,說明Rand11是有問題。
重新觀察Rand10和Rand11.在Rand10中雖然分配了2個集合,但是每個集合的元素都是相同的,但是在Rand11中2個集合,一個集合是6個元素,一個集合是5個元素,問題肯定就出現在這裏。
注意到程序運行到代碼塊2和代碼塊3的概率都是一樣的都爲1/2
只不過概率1/2被6個元素給分了(1,3,5,7,9,11),而剩下的1/2被剩餘的5個元素分了(2,4,6,8,10)
所以在輸出的結果中可以看到P(1),P(3),P(5),P(7),P(9),P(11)的概率都約等於1/12而其他數的概率約等於1/10。
現在可以這樣來考慮,爲了讓1-11這11個數都是等概率的得到,可以把概率1看成一塊蛋糕分給11個人,這個該如何分了?
可以這樣來分:先平均分成12份,每個人拿一份,最後剩下一份,然後把剩下的那一份再平均分12份,依次類推。
現在我們用數學知識來計算一個人(A)到底分配了多少蛋糕:
步驟1:第一次分12份,分給11人後,A得到了1/12,還剩下1/12
步驟2:把步驟1剩下的一份在分成12份,分給11人後, A得到了1/12 * 1/12,剩餘1/12 * 1/12
步驟3:把步驟2剩餘的一份在分成12份,分給11人後, A得到 1/12 * pow(1/12, 2) //pow(a,b)表示a的b次方
依次類推
可的A得到的蛋糕:P(A)=1/12 + 1/12 * 1/ 12 + 1/12 * pow(1/12,2) + ..... + 1/ 12 * pow(1/12, n)= (1/12) * (1- pow(1/12, 2)) / (1 - 1/12) //等比數列計算公式 = (1/12 ) / (11/12) = 1 / 11
結果爲1/11是我們想要的結果,那麼可以根據依然的想法來編寫程序:
Rand11_2
public class Rand11_2 : Rand7Base
{
private Rand11_2()
{
_maxNum = 11;
}
public static Rand11_2 GetInstance()
{
if (rand == null || !(rand is Rand11_2))
{
rand = new Rand11_2();
}
return (Rand11_2)rand;
}
//獲得隨機數
override public int Next()
{
int num;
while (true)
{
num = _rand7.Next();
if (num <= 6)
break;
}
while (true)
{
int n = _rand7.Next();
if (n == 1)
continue;
if (n > 4)
num = num * 2 - 1;//1,3,5,7,9,11
else
{
//當num = 6的時候表示需要繼續的劃分蛋糕
if (num == 6)
{
num = Next();
}
else
{
num = 2 * num;
}
}
break;
}
return num;
}
}
按照以前的方法添加測試代碼並測試
此次測試Rand11和Rand11_2,這樣可以進行比較:
計算Rand11的概率如下
產生1的概率是:0.0831913
產生2的概率是:0.1001187
產生3的概率是:0.0833342
產生4的概率是:0.0999278
產生5的概率是:0.0834714
產生6的概率是:0.1000888
產生7的概率是:0.0833103
產生8的概率是:0.1001032
產生9的概率是:0.0832276
產生10的概率是:0.1000561
產生11的概率是:0.0831706
耗時: 3.28849131413559 秒
Average:0.0909091;Max:0.1001187;Min:0.0831706
Max:0.1001187, Max-Average:0.0092096, Bits:10.1305700%
Min:0.0831706, Min-Average:-0.0077385, Bits:-8.5123400%
計算Rand11_2的概率如下
產生1的概率是:0.0908736
產生2的概率是:0.0908268
產生3的概率是:0.0908969
產生4的概率是:0.0909283
產生5的概率是:0.0909252
產生6的概率是:0.0908479
產生7的概率是:0.0908451
產生8的概率是:0.0909375
產生9的概率是:0.0909681
產生10的概率是:0.0910002
產生11的概率是:0.0909504
耗時: 2.48036752188162 秒
Average:0.0909091;Max:0.0910002;Min:0.0908268
Max:0.0910002, Max-Average:0.0000911, Bits:0.1002200%
Min:0.0908268, Min-Average:-0.0000823, Bits:-0.0905200%
這樣就出現我們所希望的結果了,也就是說我們的假設是正確的了。
既然Rand11_2可以用這樣的方法去解決了,那麼Rand10或者Rand12能不能用類似的思路去解決這個問題了?
下一篇我們來嘗試用這種思路實現Rand10.