蒙特卡羅方法(Monte Carlo method)

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ī)律可循的問題時,個人覺得這種暴力模擬的方法不失為一種好方法

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容