2017-12-27 326 views
1

我試圖在R中實現Brent-Salamin algorithm的變體。它在前25次迭代中運行良好,但後來出乎意料地返回負結果。實現算法來計算R中的R

算法我想要實現的是:

initial values: 
x_0 = 1; y_0 = 1/sqrt(2); z_0 = 1/2 

x_n = (x_n-1 + y_n-1)/2 
y_n = sqrt(x_n-1 * y_n-1) 
z_n = z_n-1 - 2^n * (x_n^2-y_n^2) 

p_n = (2 * x_n^2)/z_n 

其中n是當前迭代。

一個更漂亮的格式化公式是here

我想通了的代碼是:

mypi <- function(n){ 

    x = 1 
    y = 1/sqrt(2) 
    z = 1/2 
    iteration = 0 

    while(iteration < n){ 
    iteration = iteration + 1 

    newx = (x + y)/2 
    y = sqrt(x * y) 
    x = newx 
    z = z-(2^iteration * (x^2 - y^2)) 
    p = (2 * x^2)/z 
    } 

    return(p) 
} 

輸出:

> mypi(10) 
[1] 3.141593 
> mypi(20) 
[1] 3.141593 
> mypi(50) 
[1] -33.34323 

所以,我是新來的R,有沒有在我的代碼中的錯誤或者是它的算法?

+0

哪裏'i'從何而來? – AdamO

+0

@AdamO它應該是'iteration',而不是'i' –

+1

在玩了大約20分鐘的代碼之後,我沒有確切的答案,而且我不確定是否有解釋可能是由於浮點運算的侷限性。在我開始看到負數之前,我已經完成了將近50次的迭代。我認爲經過這麼多迭代之後,'z'中的'2 ^迭代'項變得如此之大,並且'x^2 - y^2'項變得如此之小,以至於四捨五入等開始起作用。你看到的負數只是一個神器。 –

回答

11

你的代碼只是因爲它不符合wiki頁面中寫的算法而變得混亂起來。正確的版本是這樣的:

mypi <- function(n){ 

    x = 1 
    y = 1/sqrt(2) 
    z = 1/4 
    p <- 1 

    iteration = 0 

    while(iteration < n){ 
    iteration = iteration + 1 

    newx = (x + y)/2 
    y = sqrt(x * y) 
    # x = newx 
    # z = z-(2^iteration * (x^2 - y^2)) 
    z = z- p* (x-newx)^2 
    p = 2*p 
    x = newx 
    } 

    (newx + y)^2/(4*z) 
} 

給人

> mypi(10) 
[1] 3.141593 
> mypi(20) 
[1] 3.141593 
> mypi(50) 
[1] 3.141593 
+0

好的......我不會想到檢查代碼本身的準確性+1 –

+0

謝謝你的回答。正如我在我的問題的第一句中寫的,我試圖實現算法的(給定)變體,但由於結果我不確定它的準確性。這就是爲什麼我在問題結束時詢問R代碼是否存在錯誤,或者問題是算法本身!所以如果變化超過25次迭代是錯誤的,但變化的實施是可以的,這將回答我的問題,並對我非常有幫助。那麼你是否在實現「錯誤」算法的過程中發現了任何問題? – amadeusamadeus

+0

@amadeusamadeus如果你想調試算法,我認爲math.stackexchange.com的人應該能夠幫助你。我不是100%確定你是如何派生出來的......它*看起來像Householder的一些反正切值的算法,它給出了$ \ pi $的一小部分。無論如何,你的算法匹配精美格式的公式,所以沒有問題。最後要考慮的一件事:大多數算法不是基於像您所做的那樣運行固定迭代而終止,而是當該值達到目標精度時終止。 50次迭代可能會達到浮點精度的限制... – AdamO