第5回、積分など


目次


積分など

実は先週まででおおまかな規則(サブルーチンは除く)はひととおり紹介した ことになります。 あとはこれらの組合せによって、いろいろな作業を行なっていくのです。 今日はその応用例の1つとして、積分をやってみます。いわゆる”数値積分”と 呼ばれるものです。

行列の演算

行列の計算は数値計算を行なうにあたって非常に重要な地位を占めています。 以下の例で確認しましょう。
例題1
2つの 2x2 行列を読み込み、その和、差、積を求める。
解答
       implicit real(a-h,o-z)
       integer num
       parameter (num=2)
       real a(num,num), b(num,num), c(num,num)
c
       read(5,'(2f10.5)') ((a(j,i), i = 1 , num), j = 1 , num) 
       read(5,'(2f10.5)') ((b(j,i), i = 1 , num), j = 1 , num) 
c
c      A + B
c
       do i = 1 , num
          do j = 1 , num
             c( i , j ) = a( i , j ) + b( i , j )
          end do
       end do
       write(6,'(a)') '***** A + B *****'
       write(6,'(2f10.5)') ((c(j,i), i = 1 , num), j = 1 , num)
c
c      A - B
c
       do i = 1 , num
          do j = 1 , num
             c( i , j ) = a( i , j ) - b( i , j )
          end do
       end do
       write(6,'(a)') '***** A - B *****'
       write(6,'(2f10.5)') ((c(j,i), i = 1 , num), j = 1 , num)
c
c      A * B
c
       do i = 1 , num
          do j = 1 , num
             c( i , j ) = 0.0
             do k = 1 , num
                c( i , j ) = c( i , j ) + a( i , k ) * b( k , j )
             end do
          end do
       end do
       write(6,'(a)') '***** A x B *****'
       write(6,'(2f10.5)') ((c(j,i), i = 1 , num), j = 1 , num)
c

       end
上のプログラムについて説明します。
4行目
2次元配列 A, B, Cを定義します。ここでそれぞれの行列の次元を "num"としていますが、numの値はその上で定義されています。また numの値を変えればこれらの行列の次元が全て変わり、より大次元行列の 計算用に拡張するのが非常に楽です。
6、7行目
2つの行列A, Bを読み込みます。i,jの順序に注意しましょう。こう しておかないと行方向にデータを読み込んでくれません。例えば
       read(5,'(2f10.5)') ((a(i,j), i = 1 , num), j = 1 , num) 
とすると"a11,a21,a12,a22"の 順に読み込まれてしまいます。
のこり
2つの行列の和、差、積を定義にしたがって計算していきます。


積分

例題2
つぎの関数をx=0からx=2まで積分した値をシンプソンの積分公式を 用いて求めよ。
y=sqrt(4-x2)
解答
       implicit real(a-h,o-z)
       real func, a, b, h, s, t, sumo, sume, pi
       parameter(a=0.0, b=2.0)
       integer m
       func(t) = sqrt(4.0-t**2)
c
       pi = atan(1.0)*4.0
c
       read(5,'(i8)') m
c
       h = (b-a)/m
       sumo = 0.0
       sume = 0.0

       do i = 1 , m/2-1
          sumo = sumo + func(a+h*(2*i-1))
          sume = sume + func(a+h*(2*i))
       end do
       sumo = sumo + func(b-h)
       s = ( func(a) + func(b) + 4*sumo + 2*sume )*h/3
c
       write(6,'(a,i8,a,f10.7,a,f10.7,a,f10.7)')
      $    'M = ', m, ' H = ', h, ' S = ', s,' PI = ',pi
c
       end
上のプログラムについて説明します。
6行目
関数を定義します。このような関数の定義の方法を”文関数”といいます。 注意しておかないといけないのは、文関数の定義は 必ず実行文の前で行なわなければいけない、ということです。 ここで実行文とは7行目以下の 代入文、read,writeなどをあらわします。つまりここで6行目と7行目を 逆に書くことはできない、ということです。
7行目
組み込み関数 atan (tanの逆関数)を使って、πを計算します。今やろうと している積分の値はπになりますので、シンプソンの積分公式を使った 値と比較してやろう、としているわけです。
9行目
積分区間をいくつにくぎるか、を読み込みます。
11行目
1つの区間の長さ、つまり刻み幅を計算します。
普通このような数値積分を行なう場合、計算を行なう刻み幅、つまり区間の数を 増やしていけば真の解に近付いていく、と思われます。実際微積分学はそのよう にして構築されているわけですが、この場合はそうはなりません。区間の数を 増やしていくと計算誤差の1つである 丸め誤差が蓄積されていきます。この場合は アルゴリズムを工夫するのは簡単ではありません。誤差対策の1番目である ”倍精度実数”で行なう、という方法をとります。

今日の課題


  1. 小テスト
  2. [5-1]3次元ベクトルをある行列によって一次変換するプログラムを作成せよ。
  3. [5-2]数値積分を行なう他の方法として、シンプソンの積分公式より精度は 悪いが、他に区間を台形で近似する方法がある。例題2の関数を例にとり、 台形で近似する方法、シンプソンの方法でそれぞれ積分し、両者の 計算方法を比較検討せよ。
  4. [5-3]他に数値積分を行なう方法はどのようなものがあるか?その方法と特徴を 論ぜよ。

本講義の目次へ戻る