2日目「変数を使おう」:準備
能書き
数値を計算して表示するだけなら電卓と変わりません。 「変数」と呼ばれる「(数)値を入れる箱」を使うことで、段々とプログラミングらしくなってきます。今日は変数を使って、プログラミングの第一歩を踏み出してみましょう。
ファイルを作る
1.自分の"Fortran"フォルダに、"day2.f90"というファイルを作る2."day2.f90"を開く
3.下の"program... ...end program"をコピー&ペーストする
program day2 !------------------------ ! Fortran template !------------------------ implicit none integer, parameter :: double=selected_real_kind(15) !--- begin header --- !--- end header --- !--- begin main --- !--- end main --- end program
書き換える
implicit none integer, parameter :: double=selected_real_kind(15)この2行は大切な「おまじない」です。今後は必ず書くようにしましょう。
ここでは、
!--- begin header --- 変数を宣言するところ !--- end header ---をheader部分、
!--- begin main --- プログラムを書くところ !--- end main ---をmain部分と呼ぶことにします。
Lesson 5. 変数を使おう
定義:変数の宣言
integer :: i [, j] [, 変数名] [...]header部分に書く(宣言する)ことで、『i』(変数名)を整数型の変数として使えるようになる。
real(kind=double) :: a [, b] [, 変数名] [...]header部分に書く(宣言する)ことで、『a』(変数名)を倍精度実数型の変数として使えるようになる。
宣言された変数は、main部分で使うことができる。
変数名は2文字以上も可。2文字目以降は数字も可。大文字小文字は区別しない。
コンマで区切ることで、変数をいくつも続けて宣言できる。
コンマで区切ることで、変数をいくつも続けて宣言できる。
定義:『=』(変数への代入)
変数 = (式の)値『値』を『変数』に代入する。(『値』は『変数』の型に変換される)
『値』の代わりに式を書くと、その式を評価した値が代入される。
代入後の『変数』を使うと、代入された『値』に置き換えられる。
「等号」ではなく「代入記号」です。
学習
プログラムは上から1行ずつ順番に実行され、 『=』の右辺に変数が出てくると、その時点で変数に代入されている値が左辺の変数に上書きされます。なのでたとえば
i = i + 1という文は、『i』の値を『1』増やせ、という意味になります。
変数は、使われる瞬間ごとに数値に置き換えられるものです。 Fortranにできるのはあくまで「数値」計算であって、 Mathematicaのような「解析」計算はできないことを心に留めておいて下さい。
変数の値の変化が頭の中で(難しければ紙に書いても良い)追えるようになれば、変数の扱いは一人前です。
「変数の値を追う」というのはかつてセンター試験・数学選択問題の定番でした。
実践
header部分にinteger :: i real(kind=double) :: a, bの2行を書き込んで下さい。 これで、整数型変数『i』と倍精度実数型変数『a』『b』を使えるようになります。
main部分は次のようにしましょう。
i = 0 i = i + 1 a = 1.0d0 b = 2.0d0 b = a + b a = a + b print *, "i = ", 2*i print *, "a = ", a print *, "b = ", bさて、1行1行、変数の値の変化を追って、結果を予想してみて下さい。
実行結果はこうなります。
i = 2 a = 4.00000000000000 b = 3.00000000000000外れた人は、答えが合うまで考えてみましょう。
ちなみに『2*i』を『2i』と書くことはできません。もちろん『a b』もダメです。
Lesson 6. 複素数
定義: 複素数型変数の宣言
complex(kind=double) :: z [, 変数名] [...]header部分に書く(宣言する)ことで、『z』(変数名)を倍精度複素数型の変数として使えるようになる。
学習
複素数を扱う時は、実数型変数が2つ組になったような変数、複素数型の変数を使います。 複素数の「値」は『(実部,虚部)』で表されます。complex(kind=double) :: z z = (1.0d0,1.0d0)/sqrt(2.0d0) print *, "z =", z print *, "z* =", conjg(z) print *, "z^2 =", z*z print *, "|z| =", abs(z) print *, "(z*)z =", conjg(z)*z
z = (0.707106781186547,0.707106781186547) z* = (0.707106781186547,-0.707106781186547) z^2 = (0.000000000000000E+000,1.00000000000000) |z| = 1.00000000000000 (z*)z = (1.00000000000000,0.000000000000000E+000)ここで、『abs(z)』はzの絶対値、『conjg(z)』はzの複素共役の関数です。
問題1:2次方程式を解くプログラムを作りなさい。
突然ですが、問題です。下の{かっこ}の所に入る処理を考えて、2次方程式を解くプログラムを作ってください。
complex(kind=double) :: a, b, c, z1, z2 a = (1.0d0,0.0d0) b = (-2.0d0,0.0d0) c = (3.0d0,0.0d0) {ここで2次方程式 'a z^2 + b z + c = 0' の解z1,z2を求める} print *, "kai1 =", z1 print *, "kai2 =", z25分考えて全く手がつけられなかったら、下のリンクから答えを見て下さい。
>>解答
自力で出来た!という人は、答えを見る前に検算してみましょう。
print *, "kenzan1 =", a*z1**2 +b*z1 +c print *, "kenzan2 =", a*z2**2 +b*z2 +c
答えが出たら、必ず可能な限りの方法で間違いがないか確かめる
のが数値計算の鉄則です。もちろん式、プログラムの間違いを発見するのが第一の目的ですが、たとえ式が正しくても、結果がおかしいこともある
という事実を心に刻み込んでおいて下さい。検算結果が「ほぼ0(<1.0E-15程度)」であれば正解です。
「厳密に0」にならないのは、間違いではありません。その理由は次のLessonで。
Lesson 7. 計算機特有の誤差
学習
次の結果はどうなるかわかりますか?print *, 1.0d0 -1.0d0/3.0d0 -1.0d0/3.0d0 -1.0d0/3.0d0「答えは0に決まってる」って?
思い込みは怪我の元
です。実際やってみると次のような結果になります。
1.110223024625157E-016
注:値は環境によって異なる場合があります。
小さい値(>>注)ではありますが、『0』にはなりません。これは、「倍精度実数」が「有効桁数約15桁の近似値」であるために必然的に起きることです。 コンピュータを使う以上、この誤差を完全になくすことは不可能です。
ここでは、
計算結果は『厳密に0.0d0』や『厳密に1.0d0』にはならない
という事実を心に刻んでおいてください。
計算によっては、こういった誤差が無視できなくなります。もっと詳しい話、対処法などは上級編で。