本文章是介绍几种计算PI的方法
1.概率法计算PI(又称蒙特卡罗法)
1.1 定义,过程
在半径为1的圆1/4的区域,通过随机函数产生横纵坐标值x,y;当x*x+y*y<=1时,满足条件。
1.2 结果:
因为是随机产生的值,PI的结果并不会随着样本数的增加而更接进
1.3 代码
具体代码如下
'Use Probability to calculate PI
'Another named Monte Carlo method
Sub PI_Rand()
Dim i, j
Dim num, nTime
Dim x, y, sum, PI
Dim Arr, n
Randomize (Timer) 'Random generator
nTime = 200 'number to test
'num = 100000 'Sample of random
'ReDim Arr(1 To num, 1 To 4)
For j = 1 To nTime 'Test time
sum = 0
num = nTime * j
For i = 1 To num 'Loop Range
x = Rnd
y = Rnd
If x * x + y * y <= 1 Then
n = n + 1
sum = sum + 1
PI = 4 * sum / i
End If
Next i
With Sheet11
.Cells(j + 1, 10) = j
.Cells(j + 1, 11) = num
.Cells(j + 1, 12) = PI
End With
Next j
Debug.Print Time
End Sub
2.割圆法求PI
2.1 定义,过程
2.2 结果
定义公式计算 | |||||||
Side | i | ai | bi | ci=SQRT(1-b*b) | di=1-ci | ai+1=sqrt(b*b+d*d) | PI |
6 | 1 | 1 | 0.5 | 0.866025404 | 0.1339746 | 0.51763809 | 3.00000000 |
12 | 2 | 0.51764 | 0.2588 | 0.965925826 | 0.03407417 | 0.261052384 | 3.105828541 |
24 | 3 | 0.26105 | 0.1305 | 0.991444861 | 0.00855514 | 0.130806258 | 3.132628613 |
48 | 4 | 0.13081 | 0.0654 | 0.997858923 | 0.00214108 | 0.065438166 | 3.139350203 |
96 | 5 | 0.06544 | 0.0327 | 0.999464587 | 0.00053541 | 0.032723463 | 3.141031951 |
192 | 6 | 0.03272 | 0.0164 | 0.999866138 | 0.00013386 | 0.016362279 | 3.141452472 |
384 | 7 | 0.01636 | 0.0082 | 0.999966534 | 3.3466E-05 | 0.008181208 | 3.141557608 |
768 | 8 | 0.00818 | 0.0041 | 0.999991633 | 8.3666E-06 | 0.004090613 | 3.141583892 |
1536 | 9 | 0.00409 | 0.002 | 0.999997908 | 2.0916E-06 | 0.002045307 | 3.141590463 |
3072 | 10 | 0.00205 | 0.001 | 0.999999477 | 5.2291E-07 | 0.001022654 | 3.141592106 |
6144 | 11 | 0.00102 | 0.0005 | 0.999999869 | 1.3073E-07 | 0.000511327 | 3.141592517 |
2.3 代码
具体代码如下:
'Use Cutting Circle to calculate PI
'https://zh.wikipedia.org/wiki/%E5%89%B2%E5%9C%86%E6%9C%AF_(%E5%88%98%E5%BE%BD)
'http://blog.sina.com.cn/s/blog_a6f9a3b60101ecp1.html
'Logic please refer the Chart in Worksheet
Sub PI_CutCircle_Formula_2()
Dim i%, num%, side%
Dim Ai#, Bi#, Ci#, Di#
Dim Aj#
Dim PI#
Dim m
With Sheet12
num = 10 'Large of cutting
i = 0 'time of cut
side = 6 'side of Polygon
Ai = 1
Do While i <= num 'Loop cutting range
Bi = Ai / 2
Ci = Sqr(1 - Bi * Bi)
Di = 1 - Ci
PI = side * Ai / 2 * 1 'PI=circumference/diameter
Aj = Sqr(Bi * Bi + Di * Di) 'Next Ai
m = 24 + i 'row in worksheet
.Cells(m, 6) = side
.Cells(m, 7) = i
.Cells(m, 8) = Ai
.Cells(m, 9) = Bi
.Cells(m, 10) = Ci
.Cells(m, 11) = Di
.Cells(m, 12) = Aj
.Cells(m, 13) = PI
i = i + 1 'Next Cut
Ai = Aj
side = side * 2
Loop
End With
Debug.Print Timer
End Sub
3.公式法求PI
3.1 定义,过程
3.2 结果
随着分子分母不断增加,其值不断接近PI
3.3 代码
具码如下
'Use Formula to calculate PI
'Refer Worksheet 6.4.3
'PI=2+2/3+2/3*2/5+2/3*2/5*3/7.....
'numerator+1, denominator+2
Sub PI_Formula_Calc()
Dim PI#, temp#
Dim numerator%, denominator%
Dim m, Str$
m = 6
PI = 2 'Initial
temp = 2
numerator = 1
denominator = 3
With Sheet14
Do While temp > 1E-16 '=0.0000000000000016
temp = temp * numerator / denominator
Str = "'" & CStr(numerator) & "/" & CStr(denominator)
PI = PI + temp
.Cells(m, 1) = PI
.Cells(m, 2) = numerator
.Cells(m, 3) = denominator
.Cells(m, 4) = Str
m = m + 1
numerator = numerator + 1
denominator = denominator + 2
Loop
End With
Debug.Print Timer
End Sub
4.计算任意位数的PI
4.1定义,过程
计算PI的过方法和公式法相同,不过需要将计算的结果保存到数组中,并且通过数组的计算将结果输出
4.2 结果
以下结果是1000位的PI,
4.3 代码
具体代码如下
'Calculate the PI Long Digital Number
'2+tmp*numerator/denominator
Sub Long_Digital_PI()
Dim t
Dim lenPI, i
Dim flag, count
Dim PI(), tmp()
Dim carry
Dim numerator, denominator, result
Dim Str$
Dim m%, n%
t = Timer
lenPI = 1000 'Initial lenth of PI
'Leave PI(0) AND PI(tie) for calculation use
ReDim PI(0 To lenPI) 'Allocate Array
ReDim tmp(0 To lenPI) 'Allocate Array
'Initial Number
PI(1) = 2
tmp(1) = 2
flag = 1
numerator = 1
denominator = 3
Str = ""
m = 10
'n = 0
Do While flag And count < 214748364 'Largest Int
carry = 0
For i = lenPI To 1 Step -1 'multipy numerator from Lower->High
result = tmp(i) * numerator + carry 'Each digit + carry in
tmp(i) = result Mod 10 'Reminder
carry = Int(result / 10) 'Carry in
count = count + 1
Next i
carry = 0
For i = 1 To lenPI Step 1 'divide denominator from High->Lower
result = tmp(i) + carry * 10 'reminder from previous
tmp(i) = Int(result / denominator) 'intege of current number
carry = result Mod denominator 'reminder of current number, goto next lower
count = count + 1
Next i
flag = 0
For i = lenPI To 1 Step -1 'Cumulate result
result = PI(i) + tmp(i)
PI(i) = result Mod 10 '1 digit in array
PI(i - 1) = PI(i - 1) + Int(result / 10) 'carry to high digit
flag = flag + PI(i) 'if all PI()=0 then exit sub
count = count + 1
Next i
numerator = numerator + 1
denominator = denominator + 2
If flag > 0 Then flag = 1
Loop
With Sheet13 'Output Result
n = 1
Str = PI(1) & "." 'Integer Parts
For i = 2 To lenPI
Str = Str & PI(i)
If i > 2 And (i - 2) Mod 10 = 0 Then
If (i - 2) Mod 50 = 0 Then
.Cells(m, n) = Str
m = m + 1
n = 1
Else
.Cells(m, n) = Str
n = n + 1
End If
.Cells(m, n) = Str
Str = ""
End If
Next i
End With
Debug.Print Timer - t
End Sub