簡體   English   中英

Fibonacci遞歸函數需要永遠

[英]Fibonacci Recursive function takes forever

我想獲得Fibonacci序列的第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

應用我不知道fortran我會盡我所能向你展示如何在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];
}

這是備忘的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

鑒於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 ....

順便說一下,我還測量了n = 048時調用此例程的時間。 在Xeon2.6GHz(x86_64)+ gfortran4.7.2 -O2上是91秒。 如果子程序被函數替換,則時間減少到72秒。 為了比較,我還在Julia中嘗試了以下代碼

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秒,對於這次遞歸非常有用。 另一方面,直接迭代(沒有遞歸調用)當然是超快的,只需<0.001秒。

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

以下是功能:

  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)的時間可以忽略不計。

像這樣遞歸地計算斐波那契導致重復計算遞歸與迭代(斐波那契序列) 為避免這種情況,請使用迭代算法。

這是用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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM