2014-09-28 108 views
6

我需要使用該公式來計算PI與預定義的精度:計算PI使用逆平方和

enter image description here

所以我結束了這個解決方案。

private static double CalculatePIWithPrecision(int presicion) 
{ 
    if (presicion == 0) 
    { 
     return PI_ZERO_PRECISION; 
    } 

    double sum = 0; 

    double numberOfSumElements = Math.Pow(10, presicion + 2); 

    for (double i = 1; i < numberOfSumElements; i++) 
    { 
     sum += 1/(i * i); 
    } 

    double pi = Math.Sqrt(sum * 6); 
    return pi; 
} 

所以這個工作正確,但我面臨的問題與效率。它的速度非常慢,精度值爲8或更高。

是否有更好(更快!)的方式來計算PI使用該公式?

+0

如果只執行一次,是否真的如此慢以至於有問題? – 2014-09-28 12:34:50

+0

你是否想要計算一下你正在做的一些運動? 'Math.PI'返回3.14159265358979323846,然後您可以截取或舍入您想要的小數位數...... – 2014-09-28 12:37:39

+5

嘗試在'for'語句中使用'int'。我懷疑在那裏使用雙重減慢你的速度。 – Sopuli 2014-09-28 12:37:52

回答

9
double numberOfSumElements = Math.Pow(10, presicion + 2); 

我將在實際的軟件工程術語中嚴格談論這一點,避免在正式的數學中迷失方向。只是任何軟件工程師應該知道的實用技巧。

首先觀察代碼的複雜性。執行所花費的時間嚴格取決於此表達式。您已經編寫了指數算法,您計算的值非常迅速地上升,因爲認爲增加。你引用不舒服的數字,8產生10^10或一個循環,使得計算結果爲百萬。是的,你注意到了這一點,那就是當計算機開始花費數秒來產生結果時,無論它們有多快。

指數算法不好,它們表現很差。 O(n!)的複雜度爲,因爲這個複雜度的上升速度更快,你只能做得更差。否則許多現實世界問題的複雜性。

現在,該表達式實際上是否準確?你可以用一個「肘測試」來做到這一點,它使用了一個實用的信封示例。讓我們挑選的5位精度爲目標,並把它寫出來:

1.0000 + 0.2500 + 0.1111 + 0.0625 + 0.0400 + 0.0278 + ... = 1.6433 

你可以告訴大家的增加迅速變小,它迅速收斂。你可以推斷,一旦你添加的下一個數字變得足夠小,那麼它就沒有什麼可以使結果更準確。假設當下一個數字小於0.00001時,是時候停止嘗試改進結果了。

所以你會在1 /(N * N)停止= 0.00001 => N * N = 100000 => N =開方(100000)=> N〜= 316

你表達說,停止在10 ^(5 + 2)= 10,000,000

你可以告訴你是方式關閉,循環過於頻繁,並且沒有提高最後999.9萬次迭代結果的準確性。


時間談論真正的問題,太糟糕了,你沒有解釋你如何得到這樣一個非常錯誤的算法。但是當你測試你的代碼時,你肯定發現它並不是很擅長爲pi計算更精確的值。所以你認爲通過迭代更頻繁,你會得到更好的結果。

請注意,在這個彎頭測試中,能夠以足夠的精度計算加法也很重要。我故意將這些數字四捨五入,就好像它是在一臺能夠執行5位精度加法的機器上計算的一樣。無論你做什麼,其結果都不可能是更多精確到5位數。

您在代碼中使用了類型。直接由處理器支持,它沒有無限精度。您需要牢記的唯一規則是使用double的計算永遠不會比15位數更精確。還要記住float的規則,它永遠不會比7位數更精確。

所以不管你通過什麼價值presicion,結果可能永遠比15位更精確。這根本沒用,你已經有了pi值精確到15位數的功能。它是Math.Pi

你需要做的一件事是解決這個問題,它使用的類型比double更精確。實際上,它必須是一種具有任意精度的類型,它至少需要與您通過的認定值一樣精確。 .NET框架中不存在這種類型。找到一個可以提供給你的庫是SO的common question