C プログラミング (C Programming)

[2017/10/20, H.Aman]
[← 演習のページへ戻る]

サンプルプログラム 5 の内容

整数 n を読み込み,フィボナッチ数列を表示する.
ただし,表示するフィボナッチ数列は,値が n 未満のもののみとする.
 1:   #include <stdio.h>
 2:  	
 3:   int main(void){
 4:      int n, a, b, x;
 5:
 6:      printf("整数を一つ入力してください:");
 7:      scanf("%d", &n);
 8: 
 9:      a = 1;
10:      b = 1;
11:      printf("%d %d ", a, b);
12:  
13:      x = a + b;
14:      while ( x < n ){
15:         printf("%d ", x);
16:         a = b;
17:         b = x;
18:         x = a + b;
19:      }
20:  
21:      printf("\n");
22: 
23:      return 0;
24:   }

フィボナッチ数列とは?

いきなりだと,このサンプルプログラムで何をやろうとしているのか意味が分からないと思いますので,
まずは,フィボナッチ数列というものについて説明します.

直感的な言い方をすると,単調に増加する数列の一種であり,
k 番目の値は一つ前(k-1番目)の値と二つ前(k-2番目)の値の合計になっているというものです.
ただし,1 番目と 2 番目だけは特別に 1 とします.

具体的には,1 番目と 2 番目は 1 という定義なので:
  1   1
となり,その次(3番目)は直前の二つの合計 1+1 = 2 となります:
  1   1   2
引き続き,その次(4番目)も直前の二つの合計 1+2 = 3 となります:
  1   1   2   3
同様にして,
  1   1   2   3   5
  1   1   2   3   5   8
  1   1   2   3   5   8   13
という具合いに続いていきます.

フィボナッチ数列そのものは上のルールに従って無限に続くのですが,
それでは終わりが来ないので,サンプルプログラムでは最初に入力した整数 n を終了の目安(n 未満の部分しか表示しない)としています.

9-11 行目: a = 1; b = 1; printf("%d %d ", a, b);

 7:      scanf("%d", &n);
 8: 
 9:      a = 1;
10:      b = 1;
11:      printf("%d %d ", a, b);
12:  
13:      x = a + b;

ひとまず,フィボナッチ数列での 1 番目と 2 番目だけを出力しています.

「それだけなら,わざわざ a や b という変数を使う必要はないのでは?」と思ったかもしれません.

たしかに,1 番目と 2 番目はどちらも 1 であることが(計算しなくても)わかっているので,直接 printf("1 1"); とだけ書いても構いません.
ここであえて a, b という変数を用意したのは,3 番目以降の値を求めるための準備なのです.
引き続いて,while 文を使って次々とフィボナッチ数列を作り出していきます.

13-18 行目: x = a + b; ...

 9:      a = 1;
10:      b = 1;
11:      printf("%d %d ", a, b);
12:  
13:      x = a + b;
14:      while ( x < n ){
15:         printf("%d ", x);
16:         a = b;
17:         b = x;
18:         x = a + b;
19:      }

まず,13 行目で x = a + b; としていますが,この意味を説明します.

ここでは(フィボナッチ数列として)
  • 次に出力する項」を変数 x で表すことにし,
  • 二つ前の項を変数 a,
  • 一つ前の項を変数 b としてそれぞれ考えることにします.
現時点では 1 番目と 2 番目については出力済みですので, 「次に出力する項」は 3 番目ということになります.
この 3 番目の項を x とすると,x の値は一つ前(b)と二つ前(a)の合計で求まることになりますので,
13 行目で x = a + b; としています.

while 文による繰り返しでは,
  1. まず,15 行目で x を出力する.
  2. 次に 16-18 行目では,(フィボナッチ数列での)その次の項を作っています:
    • 準備として,これまで一つ前(b)として扱っていた項ですが,次の出力では一つずれて,二つ前(a)の項という扱いに変わりますので, a = b; とします.
    • さらに,先ほど出力した値(x)が,次の項にとっては一つ前の値(b)ということになりますので, b = x; とします.
    • 最後に,次の項のための b と a が出揃いましたので,次の項 x を x = a + b; として用意します.
具体的には次のように対応します:
  a   b   x
  1   1   2
    ↓
      a   b   x
  1   1   2   3
    ↓
          a   b   x
  1   1   2   3   5
    ↓
              a   b   x
  1   1   2   3   5   8
    ↓
                  a   b   x
  1   1   2   3   5   8   13

14 行目: while ( x < n ) {

 9:      a = 1;
10:      b = 1;
11:      printf("%d %d ", a, b);
12:  
13:      x = a + b;
14:      while ( x < n ){
15:         printf("%d ", x);
16:         a = b;
17:         b = x;
18:         x = a + b;
19:      }

繰り返しをいつまで続けるかですが,「次に表示する項」である x が n 未満ならば続けるということにしておけば, フィボナッチ数列を n 未満の範囲だけ出力することになります.

21 行目: printf("\n");

14:      while ( x < n ){
15:         printf("%d ", x);
16:         a = b;
17:         b = x;
18:         x = a + b;
19:      }
20:  
21:      printf("\n");
22:
23:      return 0;

while 文での繰り返しが終わった後に,再度,改行文字を出力していますが, 改行を行わないままプログラムの実行が終わってしまって表示が見にくくなるのを防ぐためのものです.