Java利用蒙特卡洛方法求解圓周率π值

一、蒙特卡洛法介紹

蒙特·卡羅方法(Monte Carlo method),也稱統計模擬方法,是一種以概率統計理論為基礎的數值計算方法,常用於特定條件下的概率計算問題。蒙特卡羅是摩納哥的著名賭城,該法為表明其隨機抽樣的本質而命名。

算法思路簡單也好理解:比如拋一枚硬幣,假設我們開始不知道正面朝上的概率是多少,卻有大量的時間來將硬幣拋一萬次,那麼在一萬次試驗後,會發現正面朝上的次數接近一半,當然,拋的次數越多,概率越接近50%,蒙特卡洛方法是大數定律在實際應用問題上的體現。其優點十分明顯,基本可以繞開問題本身的“黑盒”,不必考慮問題內部的結構而隻關註問題的輸入與輸出,利用輸出的結果來分析問題,適用於對離散系統進行計算仿真試驗。

例如上例中,我們不用考慮硬幣在空中停留多長時間,不用考慮拋出力度、硬幣大小、空氣阻力、風速等亂七八糟的問題,在大量的試驗後隻關註最後硬幣哪面朝上,就能正確估算出硬幣正面朝上的概率。同樣的,例如我們不知道走到某個路口需要等紅綠燈的概率,不知道某個產品線的合格率,蒙特卡洛法告訴你:模擬一萬次試驗後你就知道瞭

二、利用蒙特卡洛方法計算圓周率π

采用蒙特卡洛思想,首先在一個正方形區域內隨機生成若幹個均勻分佈的點,隨後判斷哪些點在正方形的內切圓范圍內。如果點的數量足夠多,那麼圓內點的數量與點的總數量的比值,就是圓的面積與正方形面積之比。利用點數量的比值與正方形面積就可以推出圓的面積,進而得出圓周率π。

三、實現代碼

MTKLExp.java

import java.awt.*;
 
public class MTKLExp {
 
    private int squareSide;
    private int N;
    private int outputInterval = 100;
 
    public MTKLExp(int squareSide, int N){
        if(squareSide <= 0 || N <= 0)
        {
            throw new IllegalArgumentException("squareSide and N must > 0");
        }
 
        this.squareSide = squareSide;
        this.N = N;
    }
 
    public void setOutputInterval(int interval){
        if ( interval <= 0)
        {
            throw new IllegalArgumentException("interval must be > 0");
        }
 
        this.outputInterval = interval;
    }
 
    public void run(){
        Circle circle = new Circle(squareSide/2, squareSide/2, squareSide/2);
        MonteCarloPiData data = new MonteCarloPiData(circle);
 
        for(int i = 0; i < N; i ++){
 
            if( i % outputInterval == 0)
                System.out.println(data.estimatePi());
 
            int x = (int)(Math.random()*squareSide);
            int y = (int)(Math.random()*squareSide);
            data.addPoint(new Point(x, y));
 
        }
    }
 
    public static void main(String[] args){
 
        int squareSide = 800;
        int N = 1000000;
 
        MTKLExp exp = new MTKLExp(squareSide, N);
        exp.setOutputInterval(100);
        exp.run();
    }
}

MonteCarloPiData.java

import java.util.LinkedList;
import java.awt.*;
 
public class MonteCarloPiData {
 
    private Circle circle;
    private LinkedList<Point> points;
    private int insideCircle = 0;
 
    public MonteCarloPiData(Circle circle){
        this.circle = circle;
        points = new LinkedList<Point>();
    }
 
    public Circle getCircle(){
        return circle;
    }
 
    public int getPointsNumber(){
        return points.size();
    }
 
    public Point getPoint(int i){
        if(i < 0 || i >= points.size())
            throw new IllegalArgumentException("out of bound in getPoint!");
 
        return points.get(i);
    }
 
    public void addPoint(Point p){
        points.add(p);
        if(circle.contain(p))
            insideCircle ++;
    }
 
    public double estimatePi(){
 
        if(points.size() == 0)
            return 0.0;
 
        int circleArea = insideCircle;
        int squareArea = points.size();
        return (double)circleArea * 4 / squareArea;
    }
}

Circle.java

import java.awt.*;
import javax.swing.*;
 
public class Circle {
 
    private int x, y, r;
 
    public Circle(int x, int y, int r){
        this.x = x;
        this.y = y;
        this.r = r;
    }
 
    public int getX(){ return x; }
    public int getY(){ return y; }
    public int getR(){ return r; }
 
    public boolean contain(Point p){
        return Math.pow(p.x - x, 2) + Math.pow(p.y - y, 2) <= r*r;
    }
}

以上就是Java利用蒙特卡洛方法求解圓周率π值的詳細內容,更多關於Java蒙特卡洛求圓周率的資料請關註WalkonNet其它相關文章!

推薦閱讀: