第4回、繰り返しと配列


目次


繰り返しと配列

先週の課題は少し難しかったでしょうか?プログラムが上手になるコツは とにかくいろんなプログラムを読んでその考え方に慣れることですので、 どんどんチャレンジしていきましょう。

先週はプログラムの流れ(上から下へ)を変える1つの手段として、条件分岐 (IF文)と数値計算を行なうに当たって非常に重要となる誤差の話をしました。 今日はプログラムの流れを変えるもう1つの重要な方法、”繰り返し”と それに加えて”配列”の話をします。単純作業を繰り返しやらせる、という 意味においてやっと計算機を使っている、という気にさせてくれるかもしれま せん。

例題1
10個の数字を読み込み、平均、最大値、最小値を計算せよ。
解答
      implicit real(a-h,o-z)
      real sum, avg, max, min, data
      integer i, num
      parameter (num = 10) 
c
      read(5,'(f10.5)') data
      sum = data
      max = data
      min = data
c
      do i = 2 , num
         read(5,'(f10.5)') data
         sum = sum + data
         if( max .lt. data ) max = data
         if( min .gt. data ) min = data
      end do
c
      avg = sum / real(num)
c
      write(6,'(a,f10.3,a,f10.3,a,f10.3)')
     $    'average = ', avg, ' maximum = ', max, ' minimum = ', min
c
      end
上のプログラムについて説明します。
1行目
指定した範囲の文字ではじまる変数の型を宣言します。つまり”A-H,O-Zで はじまる変数を全て実数型にしなさい”という意味です。ではそれ以外の I,J,K,L,M,Nではじまる変数は?ということになりますが、FORTRANでは ”暗黙の型宣言”というものがあり、I,J,K,L,M,Nではじまる変数は 何も指定されなければ整数型として使われることになっています。
3行目
プログラム全体で使用する定数を記述します。ここで変数"num"は 型宣言していませんが、暗黙の型宣言によって整数型であることが わかります。
6ー8行目
後の処理で使う変数の初期設定を行ないます。
10行目
この行から"end do"までの間を繰り返し処理します。また繰り返しの たびに変数"I"の値を2からnum(=10)まで1ずつ増加させます。
11行目
"5,"の後ろには入力データの書式を入れます。"f10.5"の意味は ”全部で(符号も含めて)10桁、小数点以下5桁の実数”です。
12行目
読み込むデータの総和を求めます。
13、14行目
最大値、最小値を求めていきます。
19、20行目
"(a,f10.3,....)"の書式に従って出力します。この文は横に長くなり ますから、6カラム目に継続行であることを示すよう"$"があります。
いくつかのことをまとめて書いているので、混乱するかもしれません。じっくり 考えてみてください。

また DO 文を使うにあたって注意してもらいたい点は、 ”DO 文の変数は必ず整数型を使う”ということです。例えば、”1 から 100 まで 0.2ずつ増加させる”としたかった場合、

   real a
   .....
   do a = 1 , 100 , 0.2

   ..... 

   end do
としたとします。普通に考えれば問題なさそうなのですが、計算機の内部表現は "0.2"がきっちり 0.2 であるのではなく、保証されている桁数の範囲内において 0.2 であるのです。つまり変数 a が real と宣言されているのなら、8桁しか 保証されておらず、それ以下の桁に対して誤差が蓄積されていきます。これは 非常に都合が悪い。どうするのが正解かと言うと
    integer i
    real a
    .....
    do i = 10 , 1000 , 2
       a = real(i)/10.0

       .....

    end do
とすればよいのです。

例題2
n個のデータを読み込み、小さい順に並べて出力する。
解答
      implicit real(a-h,o-z)
      real data(1000), work
      integer num, i, j
c
      read(5,'(i5)') num
      read(5,'(5f10.5)') (data(i) , i = 1 , num)
c
      do i = 1 , num-1
         do j = i+1 , num
            if( data(i) .gt. data(j) ) then
               work = data(j)
               data(j) = data(i)
               data(i) = work
            end if
         end do
      end do
c
      write(6,'(5f10.5)') (data(i), i = 1 , num)
c
      end
上のプログラムについて説明します。
2行目
"data(1000)"により、配列を宣言します。この場合は1次元配列ですから、 ベクトルの成分を思い浮かべるとちょうどいいでしょう。また本件の ように読み込むデータの数がはっきりしない場合は、配列を読み込む データ数より大きめに宣言しておきます。
8ー16行目
この間の処理でdata(i)が大きい順に並べ変えられていきます。

今日の課題

  1. 小テスト
  2. [4-1]上の例題1に分散σ2、標準偏差σを求める部分を 付け加えなさい。ただし
    σ2 = Σ( xi - < x > )2/n = < x2 > - < x > 2
  3. [4-2]空間上にある n 個の点 (xi, yi, zi) (i = 1,2,...,n) の全ての2点間の距離を求めるプログラムを書きなさい。
  4. [4-3]上で紹介した並べかえ(並べかえを行なうことを”ソート”という) のルーチンは実は効率が悪い。なぜ効率が悪いのか?他のいくつかの ソートアルゴリズムと比較して議論せよ。

本講義の目次へ戻る