GitHub地址:戳我看源碼>>>>蒙特卡羅方法
概述
- 蒙特卡羅方法又稱統(tǒng)計模擬法、隨機抽樣技術,是一種隨機模擬方法
- 用事件發(fā)生的“頻率”來決定事件的“概率”。
- 用數學方法在計算機上大量、快速地模擬試驗,以獲得問題的近似解。
- 為象征性地表明這一方法的概率統(tǒng)計特征,故借用賭城蒙特卡羅命名。
應用
求PI值
思路

PI
- 用蒙特卡羅算法的思想就是隨機往正方形里打點,圓內的點個數之和近似于圓的面積,打點總數近似于正方形的面積
- PI = 4 * cirleArea / squareArea
- PI = 4 * 圓內的點 / 打點總數
代碼
const _inCircle = Symbol('inCircle')
const _calcPI = Symbol('calcPI')
const _addPoint = Symbol('addPoint')
class PI {
constructor(N = 1000000000, consoleInterval = 100000000) {
this.N = N // 預計打點次數
this.r = 100 // 半徑
this.cirleArea = 0 // 圓內點個數
this.squareArea = 0 // 已打點個數
this.consoleInterval = consoleInterval // 每打多少個點打印一次PI
}
// 判斷是否落在圓內 包含圓邊上的點
[_inCircle](x, y) {
return Math.pow(this.r - x, 2) + Math.pow(this.r - y, 2) <= Math.pow(this.r, 2)
}
// 計算目前的PI值
[_calcPI]() {
// SquareArea不包含4條邊上的點 所以加上4條邊的長度
return 4 * this.cirleArea / (this.squareArea + 8 * this.r)
}
// 隨機打點
[_addPoint]() {
// 正方形內隨機打點的坐標 結果沒有包含四天邊上的點
let x = Math.random() * 2 * this.r
let y = Math.random() * 2 * this.r
this.squareArea++
if (this[_inCircle](x, y)) {
this.cirleArea++
}
}
// 獲取并打印PI
getPI() {
for (let i = 1; i < this.N + 1; i++) {
this[_addPoint]()
if (i % this.consoleInterval === 0) {
console.log(this.cirleArea, this.squareArea, 'PI', this[_calcPI]())
}
}
}
}
// 實例化PI 獲取PI值
new PI().getPI()
打印結果

consolePI
從圖中可以看到 PI值接近于理論值 而且數據量越大越接近理論值
三門問題
描述
三門問題(Monty Hall problem)亦稱為蒙提霍爾問題、蒙特霍問題或蒙提霍爾悖論,大致出自美國的電視游戲節(jié)目Let's Make a Deal。問題名字來自該節(jié)目的主持人蒙提·霍爾(Monty Hall)。參賽者會看見三扇關閉了的門,其中一扇的后面有一輛汽車,選中后面有車的那扇門可贏得該汽車,另外兩扇門后面則各藏有一只山羊。當參賽者選定了一扇門,但未去開啟它的時候,節(jié)目主持人開啟剩下兩扇門的其中一扇,露出其中一只山羊。主持人其后會問參賽者要不要換另一扇仍然關上的門。問題是:換另一扇門會否增加參賽者贏得汽車的機率?如果嚴格按照上述的條件,即主持人清楚地知道,自己打開的那扇門后是羊,那么答案是會。不換門的話,贏得汽車的幾率是1/3。換門的話,贏得汽車的幾率是2/3。
思路
三扇門分別用1、2、3表示,隨機一扇門為有獎品的,隨機一扇門為參賽者所選擇的,如果兩者相等則參賽者不換就贏了反之失敗,如果不相等則參賽者換就一定會贏反之失敗
代碼
const _run = Symbol('_run')
const _calcRate = Symbol('_calcRate')
class MontyHall {
constructor(change = true, N = 10000000, consoleInterval = N / 10) {
this.win = 0 // 獲勝次數
this.loose = 0 // 失敗次數
this.count = 0 // 已進行次數
this.change = change // 是否改變當前選擇
this.N = N // 預計實驗次數
this.consoleInterval = consoleInterval // 每打多少個點打印一次PI
}
// 開啟一場比賽
[_run]() {
let lottery = Math.ceil(Math.random() * 3)
let player = Math.ceil(Math.random() * 3)
if (player === lottery) {
this.change ? this.loose++ : this.win++
} else {
this.change ? this.win++ : this.loose++
}
this.count++
}
// 計算概率
[_calcRate]() {
return (this.win / this.count * 100).toFixed(2) + '%'
}
// 獲取并打印rate
getRate() {
for (let i = 1; i < this.N + 1; i++) {
this[_run]()
if (i % this.consoleInterval === 0) {
console.log(this.win, i, 'rate', this[_calcRate]())
}
}
}
}
// 實例化MontyHall 獲取Rate值
new MontyHall().getRate()
打印結果

consoleRate
從打印結果可以看出如果換門 勝率基本穩(wěn)定在2/3
總結
當遇到一些沒有固定規(guī)律可循的問題時,個人覺得這種暴力模擬的方法不失為一種好方法