利用Java隨機數計算圓周率π

一、理論篇

1. 數學公式

圓面積公式:π*r*r,其中π爲圓周率,r爲圓半徑;

正方形面積公式:s*s,其中s爲邊長;

勾股定理:a*a + b*b = c*c,其中a/b分別爲直角三角形的兩個直角邊,c爲斜邊。

2. 計算方法

考慮下圖,邊長爲r的正方形內嵌了一個以r爲半徑的1/4圓。

p_w_picpath

InsideCircle面積 = 以r爲半徑的圓面積 / 4 = π*r*r/4

正方形面積 = r*r

所以, InsideCircle面積 / 正方形面積 = (π*r*r/4) / (r*r) = π/4

面由線組成,線由點組成。因此,如果有若干點均勻落入到正方形中,那麼落入InsideCircle的點的個數佔總數的比率也將會是π/4,由此將會統計出π的值。

 

二、實戰篇

1. 散彈槍計算

具體方式爲:製作一個如上圖一樣正方形木板,用散彈槍對着它一頓亂掃,最後統計彈孔個數和落點,從而得出π的值。

事實上,真的有研究人員做過這個腦洞大過黑洞的實驗,他們在 30857 個樣本中得到了 3.13 這個還算不錯的結果。

詳見:http://www.techug.com/compute-pi-with-gun

2. Java隨機數計算

作爲一個碼農,當然玩不起散彈槍這種高級玩具,那麼接下來就以代碼來玩一把。

具體思路是這樣的:r直接取值爲1.0,還需要定義一個落在正方形中的所有點的個數PointNumber,每一個點都有一個座標(x,y),x,y取值爲0.0-1.0,利用Java隨機數生成每個點,然後用勾股定理判斷該點是落在圓內還是圓外,並統計落在圓內的點的個數InsideCircleNumber,那麼π=InsideCircleNumber/PointNumber*4。當然,如果只計算一次的話,可能誤差會較大,可以再增加一個計算次數CalcTimes,然後求平均值。

按照這樣的思路的計算結果如下:

PointNumber

CalcTimes

π

最接近π的值

10000

10000

3.141617279999959

3.1416

100000

10000

3.1415569599999684

3.1416

1000000

10000

3.1415845499999953

3.141592

10000000

10000

3.1415924761886806

3.1415928

附源代碼:

package com.test.pai;

import org.apache.commons.lang.math.RandomUtils;

public class CalcPai          
{            
    public static boolean inCircle(double x, double y)            
    {            
        return (y <= Math.sqrt(1 - x * x));            
    }

    public static double CalcPaiByPointNumber(long num)          
    {            
        double inCircleNum = 0.0;            
        for (long i = 0; i < num; i++)            
        {            
            if (CalcPai.inCircle(RandomUtils.nextDouble(), RandomUtils.nextDouble()))            
            {            
                inCircleNum++;            
            }            
        }

        double pai = inCircleNum * 4 / num;

        return pai;          
    }

    public static void main(String[] args)          
    {            
        double realPai = 3.14159265;            
        CurrResult currResult = new CurrResult(0.0, realPai, 0.0);            
        long times = 10000;            
        long num = 1000000;            
        for (long i = 1; i <= times; i++)            
        {

            double pai = CalcPai.CalcPaiByPointNumber(num);          
            currResult.setTotalPai(currResult.getTotalPai() + pai);            
            double diff = Math.abs(realPai - pai);            
            if (diff < currResult.getDifference())            
            {            
                currResult.setCurrPai(pai);            
                currResult.setDifference(diff);            
            }

            System.out.println("No." + i + "/" + times + "\t" + pai + "\t" + currResult.getCurrPai() + "\t"          
                    + currResult.getTotalPai() / i);            
        }

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章