2015-05-23 29 views
1

我想要得到斐波那契數列的第48個元素 ,我可以存儲在64位整數中。我正在使用一個遞歸子程序,但它會一直持續下去。如果任何人都可以發現我的遞歸子程序有問題,我將非常感激。斐波那契遞歸函數需要永久

Integer (Int8) :: n 
Integer (Int64) :: fib64 
n = Int (48, Int8) 
Call fibonacci_genr (fib64, n) 

這裏是我的遞歸子程序

Recursive     & 
Subroutine fibonacci_genr & 
(      & 
    fb, n     & 
) 

Integer (Int64), Intent (Out) :: fb 
Integer (Int8), Intent (In) :: n 

    Integer (Int64) :: fb1, fb2 
    If (n < 2) Then 
     fb = Int (n, Int64) 
    Else 
     Call fibonacci_genr (fb1, n-1) 
     Call fibonacci_genr (fb2, n-2) 
     fb = fb1 + fb2 
    End If 
End Subroutine fibonacci_genr 
+0

你有沒有計算出需要多少次調用來遞歸計算第48個斐波納契數? (提示:很多) –

+0

只是把計數器放在你的子程序中並計算呼叫次數並打印出來 - 你會開悟的。 –

+0

你可以記住你的答案,無需查看兩次。 – t3dodson

回答

1

Appologies我不知道的Fortran I會盡我所能告訴你如何加快它的JavaScript和我最好在FORTRAN解決方案

var memo = []; 
function fib(n) { 
    if (memo[n-1]) { //check to see if you already calculated the answer 
     return memo[n-1]; 
    } 
    memo[n-1] = n <= 1 ? 1 : fib(n - 1) + fib(n - 2); 
    return memo[n-1]; 
} 

這裏是memoized FORTRAN

Integer (Int64) :: memo(48) = 0 

Integer (Int64), Intent (Out) :: fb 
Integer (Int8), Intent (In) :: n 

Integer (Int64) :: fb1, fb2 
If (memo(n) > 1) Then ! if its in the array we just use that value 
    fb = memo(n) 
Else If (n <= 2) Then 
    memo(n) = Int (1, Int64) 
    fb = memo(n) 
Else 
    Call fibonacci_genr (fb1, n-1) 
    Call fibonacci_genr (fb2, n-2) 
    memo(n) = fb1 + fb2 
    fb = memo(n) 
End If 
End Subroutine fibonacci_genr 
+0

是否存在不需要存儲所有斐波那契數字的解決方案? – Zeus

+0

@Zeus所以這個交易空間的計算時間。我非常確定,如果你不想每次計算它們,都需要一種「記住」舊值的方法。如果空間是一個問題,你可以調整它只記得每10個fib數左右。然後它會平均計算最後5個fib數。 – t3dodson

+0

@Zeus如果你可以存儲這些數字,這將更快。 – t3dodson

0

這是用Python編寫的(同樣沒有FORTRAN)。

def f(a): 
    if (a < 2): 
    return a; 
    return _f(a-2, 2, 1) 

def _f(a, n1 , n2) : 
    if(a==0) : 
    return n1+n2 
    return _f(a-1, n1+n2, n1) 

每個數字只計算一次而不是多次。 _f是一個私有函數f是一個你打電話,

注:這仍然是遞歸的,但只會調用自身48倍(N階)

+0

我錯過了什麼嗎?我的回答有什麼問題?我沒有足夠的代表評論其他職位。但是您不需要緩存數組中的所有值, –

1

鑑於Int8=1Int64=8和顯式接口,gfortran4.7.2抱怨這

call fibonacci_genr(fb1, n-1) 
          1 
Error: Type mismatch in argument 'n' at (1); passed INTEGER(4) to INTEGER(1) 

如果實際的參數被轉換爲Int8

Call fibonacci_genr (fb1, int(n-1, Int8)) 

Int8文字直接使用(感謝@francescalus)

Call fibonacci_genr (fb1, n - 1_Int8) 

該代碼似乎工作正常。但我認爲這是更易於使用integer :: n,而不是integer(Int8) :: n因爲沒有溢出的n ....

BTW我還測量了時間調用這個例程n = 048。在Xeon2.6GHz(x86_64)+ gfortran4.7.2 -O2上達到91秒。如果子程序被功能代替,時間縮短到72秒。爲了進行比較,我還嘗試了下面的代碼在茱莉亞

function fibo(n::Int) # Int defaults to Int64 
    if n <= 1 
     return n 
    else 
     return fibo(n-1) + fibo(n-2) 
    end 
end 

for inp = 0:48 
    println(fibo(inp)) 
end 

花了118秒,所以這個遞歸很不錯。另一方面,直接迭代(沒有遞歸調用)當然是超快速的,只需要012秒,時間就是0.001秒。

+0

使用Fortran-5時不會出現問題。 – Zeus

+0

@Zeus什麼是Fortran-5? – roygvib

+0

gfortran-5是gfortran的最新版本 – Zeus

1

該解決方案爲您提供斐波那契數字的線性時間(調用次數==斐波那契數字-2,只有1次調用數字1和2)。這是通過使用返回序列的兩位數字的遞歸函數完成的,以便每次調用都可以計算下一位數字並將前一位數字重新用作其返回值。如果你想調用它只接收新數字,這確實需要一個包裝函數,但這對於減少遞歸是一個小犧牲。

這裏的功能是:

integer(kind=int64) pure function fibonacci(n) 
    use iso_fortran_env 
    implicit none 
    integer, intent(in) :: n 
    integer(kind=int64), dimension(2) :: fibo 

    fibo = fib(int(n,int64)) 
    fibonacci = fibo(1) 
    end function fibonacci 

    recursive pure function fib(n) result(ret) 
    use iso_fortran_env 
    implicit none 
    integer(kind=int64), intent(in) :: n 
    integer(kind=int64), dimension(2) :: tmp,ret 

    if (n == 1_int64) then 
     ret = [1_int64, 0_int64] 
    else if (n == 2_int64) then 
     ret = [1_int64, 1_int64] 
    else 
     tmp = fib(n-1) 
     ret = [sum(tmp), tmp(1)] 
    end if 
    end function fib 

使用這些功能的時間來計算fibonacci(48)是可以忽略不計。