2017-03-23 23 views
2

我想做一個遞歸函數來計算斐波那契數列中的第n個數字。我已經爲這個問題找到了很多解決方案,但是我知道爲什麼我的工作不行。謝謝。Shell腳本來生成斐波那契數列

function fib() 
{ 
     if [ $1 -eq 1 -o $1 -eq 2 ] 
     then 
       return 1 
     else 
       let nr=$1-1 
       fib $nr 
       rez1=$? 
       let nr=$1-2 
       fib $nr 
       rez2=$? 
       let rez=$rez1+$rez2 
       return $rez 
     fi 
} 
+0

相關:http://stackoverflow.com/q/17336915/632407 – jm666

回答

4

這裏有兩個問題。首先,所有變量都是全局變量,這意味着當您進行遞歸調用時,它將覆蓋nrrez,rez1rez2的值。您可以通過聲明爲local解決這個問題:

fib() { 
    local nr rez rez1 rez2 
    if [ $1 -eq 1 -o $1 -eq 2 ]; then 
     return 1 
    else 
     let nr=$1-1 
     fib $nr 
     rez1=$? 
     let nr=$1-2 
     fib $nr 
     rez2=$? 
     let rez=$rez1+$rez2 
     return $rez 
    fi 
} 

第二個問題是,你試圖通過函數的返回狀態,通過一個數字。返回狀態是一個1字節的無符號整數,這意味着它不能大於255(在此之後它將包裝爲0)。它真的打算給出成功/失敗結果(也許有關失敗的一些信息), 0表示成功和其他任何指示錯誤嘗試使用它別的東西是自討苦吃你可以在這裏看到的結果(從功能的local美化版版本):

$ fib 11; echo $? 
89 
$ fib 12; echo $? 
144 
$ fib 13; echo $? 
233 
$ fib 14; echo $? 
121 

第14斐波那契數是377,但是這是在255所以它出來爲377-256 = 121。爲了解決這個問題,通過echo荷蘭國際集團它結果返回到標準輸出,並與$()捕捉它:

fib() { 
    local nr rez rez1 rez2 
    if [ $1 -eq 1 -o $1 -eq 2 ]; then 
     echo 1 
    else 
     let nr=$1-1 
     rez1=$(fib $nr) 
     let nr=$1-2 
     rez2=$(fib $nr) 
     let rez=$rez1+$rez2 
     echo $rez 
    fi 
} 

...但這確實有一個缺點:它要慢得多,因爲每次調用fib都必須作爲子進程運行,並且創建子進程的計算量很大。 (這實際上將解決全局變量問題,因爲變量繼承到子進程但不能從它們上去;但是它只是偶然地解決它。)

回家的教訓:shell腳本不是正確的語言這樣的事情。

1

正是在像awk比較容易的方式:

$ echo 11 | awk 'function fib(n) { 
    return n<2 ? n : fib(n-1) + fib(n-2) 
} $1+0>0 {print fib($1)}' 
89 

$ echo 35 | awk 'function fib(n) { 
    return n<2 ? n : fib(n-1) + fib(n-2) 
} $1+0>0 {print fib($1)}' 
9227465 

或者,如果你想用逗號分隔的數字:

$ echo 39 | awk 'function fib(n) { 
    return n<2 ? n : fib(n-1) + fib(n-2) 
} $1+0>0 {printf ("%'"'"'d\n", fib($1))}' 
63,245,986