接著上一篇: 隨機化算法(1) — 隨機數
在這章開篇推薦下chinazhangjie總結的隨機算法,因為咱兩看的是同一本書,所以大家也可以去參考下他的,總結的很不錯。
http://www.cnblogs.com/chinazhangjie/archive/2010/11/11/1874924.html
(順便再PS一下,小杰也是我論壇的C/C++問題求助板塊的版主,C/C++小牛)
這一章我就把書中的一個例子舉出來了,感覺雖然很簡單,但是很有意思。
用隨機投點法計算Pi值
設有一半徑為r的圓及其外切四邊形。向該正方形隨機地投擲n個點。設落入圓內的點數為k。由于所投入的點在正方形上均勻分布,因而所投入的點落入圓內的概率為(Pi*r*r)/(4*r*r)= Pi/4 。所以當n足夠大時,k與n之比就逼近這一概率。從而,PI 約等于 (4*k)/n.
如下圖:
因為代碼里用到了上一章《概率算法(1) — 隨機數》里的RandomNumber類,所以大家可以先把前一章看看。
我把這個偽隨機類再貼一遍:
const unsigned long maxshort = 65535L;
const unsigned long multiplier = 1194211693L;
const unsigned long adder = 12345L;
class RandomNumber{
private:
// 當前種子
unsigned long randSeed;
public:
// 構造函數,默認值0表示由系統自動產生種子
RandomNumber(unsigned long s = 0);
// 產生0 ~ n-1之間的隨機整數
unsigned short Random(unsigned long n);
// 產生[0, 1) 之間的隨機實數
double fRandom();
};
// 產生種子
RandomNumber::RandomNumber(unsigned long s)
{
if(s == 0)
randSeed = time(0); //用系統時間產生種子
else
randSeed = s;
}
// 產生0 ~ n-1 之間的隨機整數
unsigned short RandomNumber::Random(unsigned long n)
{
randSeed = multiplier * randSeed + adder;
return (unsigned short)((randSeed >> 16) % n);
}
// 產生[0, 1)之間的隨機實數
double RandomNumber::fRandom()
{
return Random(maxshort) / double(maxshort);
}
const unsigned long adder = 12345L;
class RandomNumber{
private:
// 當前種子
unsigned long randSeed;
public:
// 構造函數,默認值0表示由系統自動產生種子
RandomNumber(unsigned long s = 0);
// 產生0 ~ n-1之間的隨機整數
unsigned short Random(unsigned long n);
// 產生[0, 1) 之間的隨機實數
double fRandom();
};
// 產生種子
RandomNumber::RandomNumber(unsigned long s)
{
if(s == 0)
randSeed = time(0); //用系統時間產生種子
else
randSeed = s;
}
// 產生0 ~ n-1 之間的隨機整數
unsigned short RandomNumber::Random(unsigned long n)
{
randSeed = multiplier * randSeed + adder;
return (unsigned short)((randSeed >> 16) % n);
}
// 產生[0, 1)之間的隨機實數
double RandomNumber::fRandom()
{
return Random(maxshort) / double(maxshort);
}
主文件Main:
/*
* Author: Tanky woo
* Blog: www.WuTianQi.com
* Date: 2010.12.8
* 用隨機投點法計算Pi值
* 代碼來至王曉東《計算機算法設計與分析》
*/
#include "RandomNumber.h"
#include <iostream>
#include <iomanip>
#include <time.h>
using namespace std;
double Darts(long n)
{
// 用隨機投點法計算Pi值
static RandomNumber dart;
long k = 0;
for(long i=1; i<=n; ++i)
{
double x = dart.fRandom();
double y = dart.fRandom();
// 在圓內
if((x*x+y*y) <= 1)
++k;
}
return 4 * k / double(n);
}
int main()
{
// 當進行1,000次投點時
cout << Darts(1000) << endl;
// 當進行10,000次投點時
cout << Darts(10000) << endl;
// 當進行100,000次投點時
cout << Darts(100000) << endl;
// 當進行1,000,000次投點時
cout << Darts(1000000) << endl;
// 當進行10,000,000次投點時
cout << Darts(10000000) << endl;
// 當進行100,000,000次投點時
cout << Darts(100000000) << endl;
return 0;
}
* Author: Tanky woo
* Blog: www.WuTianQi.com
* Date: 2010.12.8
* 用隨機投點法計算Pi值
* 代碼來至王曉東《計算機算法設計與分析》
*/
#include "RandomNumber.h"
#include <iostream>
#include <iomanip>
#include <time.h>
using namespace std;
double Darts(long n)
{
// 用隨機投點法計算Pi值
static RandomNumber dart;
long k = 0;
for(long i=1; i<=n; ++i)
{
double x = dart.fRandom();
double y = dart.fRandom();
// 在圓內
if((x*x+y*y) <= 1)
++k;
}
return 4 * k / double(n);
}
int main()
{
// 當進行1,000次投點時
cout << Darts(1000) << endl;
// 當進行10,000次投點時
cout << Darts(10000) << endl;
// 當進行100,000次投點時
cout << Darts(100000) << endl;
// 當進行1,000,000次投點時
cout << Darts(1000000) << endl;
// 當進行10,000,000次投點時
cout << Darts(10000000) << endl;
// 當進行100,000,000次投點時
cout << Darts(100000000) << endl;
return 0;
}
通過代碼可以看出,隨機投點越多,則越接近與3.1415926…
這個和拋硬幣時求硬幣正反面概率類似,實驗次數越多,則越接近于理論值。
下一章是《隨機化算法(3) — 舍伍德(Sherwood)算法》
Tanky Woo原創,歡迎轉載,轉載請附上鏈接,請不要私自刪除文章內任何關于本博客的鏈接。