3日目「繰り返し処理」:準備

能書き

コンピュータは繰り返し同じ事をするのが得意です。 複雑な問題を「単純作業の繰り返し」に置き換えて解かせることが、プログラミングの目標と言えます。
今日は「繰り返し」の感覚をつかんでください。

ファイルを作る

1.自分の"Fortran"フォルダに、"day3.f90"というファイルを作る
2."day3.f90"を開く
3.下の"program... ...end program"をコピー&ペーストする
program day3
 !------------------------
 ! Fortran template
 !------------------------
 implicit none
 integer, parameter :: double=selected_real_kind(15)
 !--- begin header ---

 !--- end header ---
 !--- begin main ---
  
 !--- end main ---
end program

今更ですが

 !コメント文
『!』の右側は「コメント文」と言って、プログラムとは関係のない文章(主に説明)です。 何を書いても構いませんし、もちろん消しても構いません。
丁寧に説明文を書き込んでおくことで、後で自分が見たとき・他人が見たときにわかりやすくなります。
Lesson 8. 繰り返し処理

定義:doループ

 do 整数型変数名 = 始値, 終値 [, 増分]
  {処理}
 end do
『整数型変数名』を『始値』として{処理}を実行、
『end do』まできたら『整数型変数名』を+1(または、+『増分』)して{処理}を実行、
『end do』まできたら『整数型変数名』を+1(または、+『増分』)して{処理}を実行、
...
これを繰り返し、最終的に『整数型変数名』=『終値』となるまで{処理}を繰り返し実行する。
C++など他のプログラミング言語でも同様の命令があります。

実践

定義を見るとややこしいですが、使ってみればすぐにわかるでしょう。
 integer :: i
 do i=1,5
    print *, "i = ", i
 end do
結果はこうなります。
 i =  1
 i =  2
 i =  3
 i =  4
 i =  5
『i』を1から5まで変えながら、『do』と『end do』の間を5回実行しろ、という意味です。
『i』は繰り返しの回数を表すと同時に、整数型変数としてループ内で使うことができます。 ただしループ内で値をいじることは禁止です。
繰り返しの「回数」を表すループ変数は、実数型にしてはいけません。必ず整数型にしてください。 もし実数型の『x』を『1.0d0』から『5.0d0』まで変えたいときは次のようにします。
 integer :: i
 real(kind=double) :: x
 x = 0.0d0
 do i=1,5
    x = x + 1.0d0
    print *, "x = ", x
 end do
ループごとに、『x』の値が1.0d0ずつ増えていきます(>>復習)
Lesson 9. 変数の初期化

学習: 変数の初期値

変数は、宣言された時点では値が「不定」である
というのがFortranの仕様です。 つまり、一度も値を代入せずに変数を使う(参照する)と、規則性のない値が出てくることになります。 試しに以下のようなプログラムを実行すると、
 integer :: i1,i2,i3,i4
 print *, i1,i2,i3,i4
コンパイラによってはエラーになります。
           0           0           0       32767
という結果になりました。この値には意味が無く、時と場合により異なります。 「たまたま0になることが多い」というのがくせ者で、 「今までちゃんと動いてたのに、急に変な値が出た」という面倒なバグを引き起こします。
変数を使う前には、必ず「初期化」(何か値を代入)するのを忘れないで下さい。

実践:「変数の初期化」

1から10までの自然数の和を求めるプログラムを作ってみましょう。
面倒くさくても、コピー&ペーストせず自分の手で打ち込んだほうが練習になりますよ。
 integer :: i, n, nSum
 
 n = 10
 nSum = 0   ! initialize nSum
 do i=1,n
    nSum = nSum+i
 end do
 print *, "sum is ", nSum
ここで、
    nSum = nSum+i
というのは、「今の『nSum』の値を『i』だけ増やしたものを新しい『nSum』にしろ」という意味です。 ここでは命令が実行される前の『nSum』の値が重要で、 スタート地点を『nSum=0』とするのを忘れると、とんでもない値から始まってしまうことがあります。
変数は、参照する前に必ず初期化すること

実践:「変数のリセット」

「変数を何度も使う」時は、その都度適切に初期化(リセット)する必要があります。
下のプログラムは、自然数の和を「和の公式」と「ループ」で計算して比べる(間違った)プログラムです。
 integer :: i, n, nSum
 
 n = 10
 !- formula version -
 nSum = n*(n+1)/2
 print *, "(formula) sum is ", nSum
 !- loop version -
 do i=1,n
    nSum = nSum+i
 end do
 print *, "(loop)    sum is ", nSum
何がおかしいか分かりますか?プログラムを正しく書き換えてみましょう。
ループの前後での変数の値の変化をきちんと把握できるようになれば、ループの扱いは一人前です。
ちなみに、『(1/2)*n*(n+1)』は常に『0』です(>>復習)。気をつけましょう。
Lesson 10. キーボードからの入力

定義:read文(標準入力)

 read *, 変数名
プログラム実行を一時停止し、キーボードからの入力を待つ。
入力された値は『変数名』に代入される。

実践

キーボード入力を使った対話型のプログラムを組むと、格段に使い勝手が良くなります。
上の「自然数の和」のプログラムに導入してみましょう。
 n = 10
の部分を、
 print *, "n = ?"
 read  *, n
に置き換えて下さい。
何度か実行してみましょう。いちいちプログラムを書き換えてコンパイルし直すより楽ですね。
"n = ?"を表示するのは親切のためです。

問題2:nの階乗を求めるプログラムを作りなさい。

本日の問題です。
いろいろな『n』で計算させてみて、答えが正しいことを確かめましょう。
ただし、『n』は10以下で試しましょう。値が大きすぎると桁があふれてしまいます。
答えが合わない人は、n=1のときの変数の値の変化を追ってみて、それでもダメなら解答を見てください。
>>解答