• ベストアンサー

フィボナッチ数列をつくってみたけれど・・・

ちょうど学校でフィボナッチ数列の話題になったので、思いつきで作ってみました。 そこで、配列を使ったものと再帰呼び出しを使ったものを作りました。 //再帰呼び出し unsigned long Fibonacci(int n){ if(n==1){ return 1;} //初項 else if(n==2){ return 1;} //第2項 return Fibonacci(n-1) + Fibonacci(n-2); } //配列 unsigned long Fibonacci(int n){ unsigned long long f[101]; int i; f[1] = 1; f[2] = 1; for( i=3; i<=n; i++){ f[i] = f[i-1] + f[i-2]; } return f[n]; } この二つを比較すると明らかに配列の方が早いです。 ということは再帰呼び出しはあまり使わない方がよいってことですよね? この場合は配列も似たような感じで見ることができますし。 それとも自分の再帰の書き方が悪いのでしょうか。

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.1

>この二つを比較すると明らかに配列の方が早いです。 >ということは再帰呼び出しはあまり使わない方がよいってことですよね? いいえ、違います。 求める項nが「ある程度以下」なら配列で処理出来ますが、もし、項nが大きく、それだけの配列を確保出来ない場合、遅いと判ってても再帰を使わざるを得ない場合があります。 >それとも自分の再帰の書き方が悪いのでしょうか。 「再帰関数が何回呼び出されるか?」を考えれば「再帰が如何に遅いか」が判ります。 項nの呼び出し回数は「項nのフィボナッチ数×2-1」です。n=10のフィボナッチ数は55ですから、55×2-1=109で、109回も呼び出されます。 最後に、再帰呼出も配列も使わない(nに制限がなく、スピードも速い)関数を書いておきます。参考にして下さい。 unsigned long Fibonacci(int n) {   int i;   unsigned long a,b,c;   for (i=1,a=0,b=1;i<n;i++) {     c=a+b;     a=b;     b=c;   }   return b; }

yata16
質問者

お礼

>求める項nが「ある程度以下」なら配列で処理出来ますが 一応nがそんなに大きくならなくてもn項目の値がとても大きかったので、配列でもいいか、と思ってやってみました。 でも、配列も再帰も使わなくてもできるんですね。 とても参考になりました。 ありがとうございました。

その他の回答 (2)

  • chirubou
  • ベストアンサー率37% (189/502)
回答No.3

高速化についてはいろいろと議論があると思いますが。 「この二つを比較すると明らかに配列の方が早いです。 ということは再帰呼び出しはあまり使わない方がよいってことですよね? この場合は配列も似たような感じで見ることができますし。 それとも自分の再帰の書き方が悪いのでしょうか。」 世の中、プログラムは速く動く事も重要ですが、「キレイに書く/他人が読み易く書く」という事も重要です。 再帰で書くと、フィボナッチの定義により近いと思いませんか?まあ、配列を使わない程度しか違いませんが。 大きなプログラムを、あるいはあなたがオープンソースを書いたとして、他人があなたの書いたプログラムを見て、何をしているのか理解しようとすることがあるとしましょう。この時、プログラムにコメントを入れる事も手助けになりますが、プログラムだけでも「キレイに」(要は他人から見られることを意識する、という意味)書いてあれば、理解の助けになると思いませんか? 職業でプログラムを書いていると、多くの場合、正しく動くことが一番重要で、速さはその次になったりします。多分、フィボナッチの授業は再帰呼び出しが数学的な再帰によくマッチして「キレイ」だ、という事を理解するのが目的だったのではないでしょうか。 P.S. 細かいようですが、C プログラマならば f[0] から始めて欲しかった.....

yata16
質問者

お礼

一応f[1]から始めたのは、なるべく数列に近づけようと思ったからです。 自分なりに見やすいかな、と思い、f[1]からにしました。 ちなみにフィボナッチの話は仲の良い数学の先生と「美しい!」ということで盛り上がったので・・・。 Cは独学です。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

#1 でも書かれてますけど, Fibonacci 数列は「再帰的に定義されているけど本当に再帰で計算するととても時間がかかる」例でよく使われますね. まあ, Fibonacci 数列に限らず, (漸化式で) 再帰的に定義されてる数列はみんなそうなんですが. で普通は #1 のようにループで計算するわけですが, 計算量的には行列の乗算を使うとか「閉じた式」を使うのが最適だったはず.

yata16
質問者

お礼

色々な求め方があっておもしろいですね。 ありがとうございました。

関連するQ&A

  • フィボナッチ数列 プログラミング C言語

    「フィボナッチ数を次の手順で求めるプログラムfib2.cを作成。 再帰関数 int fib(int n)を定義し,再帰呼出しによりfib(n)の値を求める。n=30までのフィボナッチ数を求めて表示せよ。 またどのnの値まで求めるか?」という問題です。 で下記のように作りましたが再帰関数をつかわなかったので再提出になってしまいました。 再帰関数はどうやって使うのでしょうか。 今回の場合はどの部分が再帰関数になるのでしょうか? おねがいします。 #include<stdio.h> main() { int fib[100], i; fib[0] = 0; fib[1] = 1; printf("F0=0\nF1=1\n"); for(i=2; i<=30; i++) { fib[i] = fib[i-1]+fib[i-2]; printf("F%d=%d\n",i, fib[i]); } }

  • フィボナッチ数列の配列について

    public class Fibonacci { public static void main(String[] args) { int [] fibAray = new int [20]; //フィボナッチ数列用の配列 fibAray[4] = 3; fibAray[1] = 1; for (int i = 0; i < fibAray.length; i++) { fibAray[i] = i + 1; } for (int i = 0; i < fibAray.length; i++) { System.out.println( "第" + (i + 1) + "頁は" + 3); } } } フィボナッチ数列の第20項までを配列にし、それらを"第4項は3"のように表示する。 という問題で作ったプログラムですが1項~20項まで3と表示されます。 これで合ってるのでしょうか?

    • ベストアンサー
    • Java
  • フィボナッチ数列の求め方

    配列を使ったフィボナッチ数列の10番目の求め方がよくわかりません。 一応自分でつくったのをのせます。最終的にfibona(10)=55というふうにしたいです。 #include <stdio.h> int main(void){ int i; int result[11]; result[0]=1; result[1]=1; for(i=2;i<=10;i++){ result[i]=result[i-1] + result[i-2]; }; printf("fibona(10)=%d\n",result[10]); }; return(0); }

  • フィボナッチ数列

    C言語の問題です。 フィボナッチ数列について。 以下のプログラムはある整数を入力し、その整数以下のもっとも大きなフィボナッチ数列に含まれる整数を返すものである。 #include <stdio.h> int main(void){ int limit,new=1,pre=0,work result; scanf("%d", &limit); while(new<=limit){ /*printf("%d %d\n,pre,new);トレース用*/ work=new; new=work+pre; pre=work; } result =pre; printf("%d\n", result); } 以下を参考に、このプログラムの一部を関数にして書き換えなさい。 #include <stdio.h> /*ここに関数を記述*/ int main(void){ int limit,result; scanf("%d",&limit); result = fibnum(limit); printf("%d\n", result); } という問題です。 私は以下のように考えたのですが… #include <stdio.h> void fibnum(int limit){ int f0, f1; f0 = 0; f1 = 1; printf("%d\n", f0); printf("%d\n", f1); while(1){ f0 += f1; if (f0 > limit)return; printf("%d\n", f0); f1 += f0; if (f1 > limit)return; printf("%d\n", f1); } } int main(void){ int limit, result; scanf("%d",&limit); result = fibnum(limit); printf("%d\n", result); return result; } 実行すると 「S:\デスクトップ\v\v.cpp(30) : error C2440: '=' : 'void' から 'int' に変換することはできません。(新しい動作 ; ヘルプを参照) void 型の式は他の型へ変換できません。 cl.exe の実行エラー」 と出てきてしまいます。 考えてみたのですが、エラーの理由がよくわかりません。 どこが間違っているのかなど、ご指摘いただければ嬉しいです。

  • フィボナッチ数列 c言語

    c言語でフィボナッチ数列を求めるプログラムを再帰関数をつくり作れという問題でしたのように作りました。 windowsでcygwinというものを使ってコンパイルしています #include <stdio.h> int fib(int); main() { int n,i; printf(\"第何項までのフィボナッチ数? n=\"); scanf(\"%d\",&n); fib(0)=0; fib(1)=1; for(i=2;i<=n;i++){ print(\"f(%d)=%d\",n, fib(n));} } エラーは $ gcc fib2.c fib2.c: In function `main\': fib2.c:10: error: invalid lvalue in assignment fib2.c:10: error: invalid lvalue in assignment とでました。 どこかちがいますか?

  • フィボナッチ数列について。

    フィボナッチ数列 F[1]=1, F[2]=1, F[n+2]=F[n+1]+F[n] (n≧1) について、 F[n] (n≠5) が素数 ならば F[n] ≡ ±1 (mod n) であることを示してください。 よろしくお願いします。

  • フィボナッチ数列のプログラム

    問題で フィボナッチ数列のn番目の値を計算する関数 int fib(int n) を再帰的に定義し、この関数を利用してフィボナッチ数列の最初の10個を表示するプログラムを書けという問題があるのですが、大まかな流れは想像できるのですが、できないので困っております。  何方か教えてください。

  • 【C言語】フィボナッチの配列について

    フィボナッチの配列を表示するプログラムについてご質問でございます。 F[i]の計算というプログラムでございます。但し、F1=F2=1,n>2のとき、Fn-1+Fn-2=Fnでございます。 #include<stdio.h> #define N 10 int main() { int i,F[N+1]; / F[i]の計算 / for(i=1;i<=N;i++){ printf("%d\n", F[i]); } } この内、「/ F[i] の計算 /」の部分が分からず、困っております。 教えて頂けたら幸いです。

  • フィボナッチ数列を使ったプログラミング

    プログラミング初心者です。 フィボナッチ数列を使ったプログラミングのお題が出ましたが、 このフィボナッチ数列(学校で習った記憶がありません)につまづき、 途中まで書いたプログラムが正しいか、どこか抜けいているのか、わからなくなってしまいました。 アドバイス頂けると幸いです。 お題) 整数を入力後、フィボナッチ数とフィボナッチ数の合計を計算して表示せよ。 なお、整数3以下の場合を入力した際は、エラーメッセージ”3以上を入力”を表示する。 *最初2項は、フィボナッチ数は1、1となる。 下記、スードコードで書いてみたドラフトです。フィボナッチ数列の式の中に出てくるnがindexを意味すると解釈し、index=n=0としたのですが、、 Fibonacci Declare num, Fibonacci number As integer num=0 fibN=0 index=n=0 sum=0 Prompt num Get num If(num<=3) Display”Error : whole number must be greater or equal to 3.” Else For(index=2; index<=num; index++) fibN=(1.0/sqrt(5))*(pow(1+sqrt((5))/2.0,n)-pow((1-sqrt(5))/2.0,n)) Display fibN EndFor Display sum=sum+finN EndIf END アドバイス、およびサンプルのプログラミングも掲載して頂けると幸いです。 なにせ初心者なので、わかりやすく説明頂けると有難いです。 よろしくお願い致します。

  • フィボナッチ数列に関する問題です

    写メにある定義でgi(n)(i=1、2、3、4)に対して、漸化式gi(n+1)=gi(n)+gi(n-1)が成り立つことを示し、各gi(n)をフィボナッチ数列f(n)を使って示せ。という問題です とても困っています。お願いします。

専門家に質問してみよう