実際に天文学の研究をするという観点からは、多くの場合に様々な言語を使う 必要に迫られる。というのは、観測的研究、理論的研究のどちらにしても、 (本当に「紙と鉛筆」だけでできる理論的研究の一部を別にすれば)計算機を使っ てデータ解析やシミュレーションをすることが必須であり、そのためのプログ ラムを作る必要がある。ところが、こういったプログラムは大規模・複雑なも のになってきており、一人でゼロから書けるものではなかなかない。何人もが 共同で作ったり、また、過去に別の人が作ったものを変更・改良して使うこと が普通である。このために、過去の資産が Fortran であれば Fortran が使え ないといけないし、C であればそれでなんとかする必要がでてくる。
この講義では Fortran を扱い、計算天文学 II では C++ を扱うことにする。 2 種類の非常に違う言語を短期間に扱うのは混乱を招く面もあることは否定し ないが、逆に言語1つだけしか知らないと、2番目を学ぶのは非常にハードルが 高いからである。2つの言語を一応理解していると、その間には共通点と相違 点があることが分かり、さらに他の言語を理解する必要ができた時にも類推が 効くようになる。
FORTRAN は、1950年代に開発された言語で、計算機言語としては、歴史が古い。進歩 の速い計算機に関しては、歴史が古いという事は、多くの場合、陳腐で劣る事を意味 する事が多い。事実、50年代或いはそれ以後開発された言語で、今日では使用されな くなった言語は非常に多い。そういった環境の中にあっても、FORTRAN は、色々な意 味で、優れた点を多く持った言語なので、様々な改良を加えられながら、今日まで、 科学計算用の標準的言語の一つとして、使われ続けている。その特徴としては、
なお、Fortran の言語仕様には、 Fortran 66, 77, 90 とほぼ 10年毎に大き な改訂が加えられてきた。この講義では、基本的には 77 に準拠するが、 90 での拡張をある程度取り入れた形でプログラムを書く。現在広く使われている のがその形であり、また計算機室のシステムで利用可能なのもそれだからである。
計算機の演算能力を最大限に発揮するには、計算機が直接理解できる機械語(アセン ブラ)でプログラムを書けば良いのだが、このためには、プログラムを書く人間の側 に多大の努力を要し、効率悪く、とても一般の人向きではない。そこで、FORTRAN 等、 人間が理解しやすい言語でプログラムを書き、それを機械語に翻訳させる作業(コン パイルという)を計算機自身にさせる訳だが、FORTRAN には、高速にしかも最適化され た機械語に翻訳する技法が進んだ形で取り入れられている。これらの理由から、 FORTRANは長い間多く利用され、それが更に、ライブラリを完備させる等、良い方向に フィードバックされて、より便利な道具として使われる理由となっている。
FORTRAN を使って計算をしたい時には、FORTRAN の言語で書かれた一つのファイルを
先ず作らなければならない。こういったファイルをプログラムと呼ぶ。例として、球
の半径が与えられた時に、球の表面積と体積を求める計算を考えよう。そのためのプ
ログラムの例は、第
章で、エディタを使ってのファイル作成練習で書い
た、sphere.fである。念のため、下に掲げておこう
。
Program sphere
Implicit NONE
c constant:
Real PI
Parameter (PI=3.141593)
c local variable:
Real radius
Real area, volume
c begin:
radius = 10.0
area = 4. * PI * radius**2
volume = area * radius /3.
Write(*,*) 'radius:',radius
Write(*,*) ' surface area =',area,' volume =',volume
c end:
Stop
End
例.
a = 1.0
b = a + 1.0
| 演算 | FORTRAN | 例 |
| 加算 | x + y | |
| 減算 | x - y | |
| 掛算 | x * y | |
| 割算 | x/y | |
| 冪乗 | x**y | |
| 括弧 | (2.*(x + y))/(3.*(a + b)) |
Implicit NONE
Parameter (PI=3.141593)
がそうだ。最初の例は、そのプログラムで使用する変数は全て型宣言をしてから
使う事を宣言している。FORTRAN では、最初の文字によって、計算機が型を暗黙
のうちに解釈するという、便利なような恐ろしいような約束事がある。一見便利
なようなルールだが、プログラムを書き直したり、長いプログラムを書く時等、
使う変数をきちんと把握している方が、結局は便利である事の方が多い。
Implicit NONEをプログラムの頭で宣言しておくと、
型宣言していない変数をプログラム中で引用していたら、計算機が警告してくれる。
| 型 | FORTRAN | 大きさ |
| 整数型 | Integer |
|
| Integer*4 |
|
|
| 実数型 | Real |
|
| Real*8 |
|
|
| 複素数型 | Complex | (有効数字7桁) |
| Complex*16 | (有効数字15桁) | |
| 論理型 | Logical | .true.(真)或いは .false.(偽) |
| Logical*2 | ||
| 文字型 | Character*サイズ | サイズ分の長さの文字列 |
二番目の例のParameter文は、変数PIの値を指定している。式として 書いても同じ事だが、物理定数等このParameter文を用いて宣言すると、 値を直す時等、場所が決まっているから、便利である。
DIMENSIONの宣言は、良く使うであろう。
等を変数として、
使いたい時がある。この様な時、
DIMENSION y(10)
の様に宣言すると、y(1), ... , y(10) が使えるようになる。引数が
二次元ならば、
DIMENSION y(i,j)
の様にすれば良い。iとjは、それより前の
Parameter文でサイズを宣言して
おけば良い。
Write(*,*) 'radius:',radius
Write(*,*) ' surface area =',area,' volume =',volume
が、WRITE文である。'radius:'はradius:と表示させる事を意味し、
カンマに続くradiusは、変数radiusの値を表示させる事を意味している。
if (code.eq.1) then
...
else
...
end if
或いは次の様な更に細かい条件分岐も出来る。
if (code.gt.1) then
...
else if (code.eq.1) then
...
else
...
end if
y = 0.0
Do i=1,10
y = y + a(i)
End do
iが10以下である限り繰り返すといった場合には、次の様なDo whileが便
利だ。
i = 1
Do while (i.le.10)
y = y + a(i)
i = i + 1
End do
。
Program sphere2
Implicit NONE
c constant:
Real RADIUS_INITIAL,MAX_RADIUS,DELTA_R
Parameter(RADIUS_INITIAL=1.0,MAX_RADIUS=10.0)
Parameter(DELTA_R=2.0)
c local variable:
Real radius
Real area, volume
c begin:
radius = RADIUS_INITIAL
Do while (radius .le. MAX_RADIUS)
Call calculation(radius, area, volume)
Write(*,*) 'radius:', radius
Write(*,*) ' area =',area,' volume =',volume
Write(*,*)
radius = radius + DELTA_R
End do
Stop
End
Subroutine calculation(radius, area, volume)
Implicit NONE
c input:
Real radius
c output:
Real area, volume
c constant:
Real PI
Parameter (PI=3.141593)
c begin:
area = 4. * PI * radius**2
volume = area * radius /3.
Return
End
メインプログラムでは、半径を与えるだけで、計算はサブルーチンcalculation
で行っている。そしてメインプログラムとサブルーチンとの間のやり取りは、メイン
プログラム中のcall文で行う。その際、引数(radius,area,volume)は、
radius がメインプログラムから与えられ、areaとvolumeは、サブ
ルーチンから計算の結果として、メインプログラムに返される。
それぞれの引数の型は、メインプログラムとサブルーチンの間で必ず一致させなけれ
ばならない。但し、引数の名前は両者の間で異なっていても構わない。
この例に見るように、引数はメインプログラムからサブルーチンにも渡せるし、
逆にサブルーチンからメインプログラムにも渡せる。どちらからどちらに渡されてい
るかは、一見して明らかな訳ではないので、上のサブルーチンcalculationの
例のように、コメントで注釈を附けておくと、便利である。
また、サブルーチンから、別のサブルーチンを呼ぶことも出来る。
サブルーチンはReturnとEndで終わるのが約束である。
。
(サブルーチンcalculationは再掲していない。)
Program sphere3
Implicit NONE
c constant:
Real RADIUS_INITIAL,MAX_RADIUS,DELTA_R
c local variable:
Real radius
Real area, volume
c begin:
Write(*,*) 'Input RADIUS_INITIAL:'
Read(*,*) RADIUS_INITIAL
Write(*,*) 'Input MAX_RADIUS:'
Read(*,*) MAX_RADIUS
Write(*,*) 'Input DELTA_R:'
Read(*,*) DELTA_R
radius = RADIUS_INITIAL
Do while (radius .le. MAX_RADIUS)
Call calculation(radius, area, volume)
Write(*,*) 'radius:', radius
Write(*,*) ' area =',area,' volume =',volume
Write(*,*)
radius = radius + DELTA_R
End do
Stop
End
Read(*,*)が、端末から変数を読み込ませるときに用いる文である。
。
Program sphere4
Implicit NONE
c constant:
Real RADIUS_INITIAL,MAX_RADIUS,DELTA_R
c local variable:
Real radius
Real area, volume
c file open:
Open(Unit=2,File='Input.dat',Status='OLD')
Open(Unit=3,File='Output.dat',Status='NEW')
c begin:
Read(2,*) RADIUS_INITIAL,MAX_RADIUS,DELTA_R
radius = RADIUS_INITIAL
Do while (radius .le. MAX_RADIUS)
Call calculation(radius, area, volume)
Write(3,*) 'radius:', radius
Write(3,*) ' area =',area,' volume =',volume
Write(3,*)
radius = radius + DELTA_R
End do
Stop
End
(*,*)のところが(2,*)となったため、入力は2番の論理装置から行なわれ る。その2番の論理装置がInput.datという名前の既製のファイルである事を 最初のOpen文が記述している。 Write文が、(3,*)であるから、出力は 3番の論理装置に対してなされる。 二つ目のOpen文は、同様に3番の論理装置がInput.datという名前の の新規のファイルである事を記述している。
で、Read文が(2,*)ではなく、(2,*,end=900)となっている事に
注意しよう。これは、N回までDOループが回ろうとしているうちに、
読み込みデータがなくなったら、900番の文番号に飛ぶ事を意味している。
900番の文では、その時点での変数iを書き出すように命令しているから、
これにより、幾つデータを読んだかが判る。この様な場合、DO文は、途中で割
り込みが入ることになり、完結しないことに注意しておこう。
Program sphere5
Implicit NONE
c constant
Integer N
Parameter(N=2000)
c local variable:
Real radius
Real area, volume
integer i
c file open:
Open(Unit=2,File='Input.dat',Status='OLD')
Open(Unit=3,File='Output.dat',Status='NEW')
c begin:
Do i=1,N
Read(2,*,end=900) radius
Call calculation(radius, area, volume)
Write(3,*) 'radius:',radius,' area =',area,' volume =',volume
End do
900 Write(*,*) 'number of data=', i-1
Stop
End
このプログラムで、N以上読み込みデータがあると、number of data
として正しくない答えNを表示する。
| FORTRAN | 意味 | FORTRAN | 意味 |
| sqrt(x) | exp(x) | ||
| log(x) | log10(x) | ||
| sin(x) | asin(x) | ||
| cos(x) | acos(x) | ||
| tan(x) | atan(x) | ||
| sinh(x) | cosh(x) | ||
| tanh(x) | abs(x) | ||
| int(x) | float(n) | 整数 |
|
| max(x,y,z,...) | min(x,y,z,...) |
混合演算をしないように、と書いたが、実数xを整数に型変換するには、 int(x)を使い、整数xを実数に型変換するには、float(x)を 使う。
real function S(r)
implicit NONE
c constant:
real PI
parameter (PI=3.141593)
c local variable:
real r
c begin:
S=4.*pi*r**2
return
end
real function V(r)
implicit NONE
c constant:
real PI
parameter (PI=3.141593)
c local variable:
real r
c begin:
V=4./3.*pi*r**3
return
end
で定義して、メインプログラムからは、
Program sphere6
Implicit NONE
c constant:
Real RADIUS_INITIAL,MAX_RADIUS,DELTA_R
c local variable:
Real radius
Real area, volume, S, V
c begin:
Write(*,*) 'Input RADIUS_INITIAL:'
Read(*,*) RADIUS_INITIAL
Write(*,*) 'Input MAX_RADIUS:'
Read(*,*) MAX_RADIUS
Write(*,*) 'Input DELTA_R:'
Read(*,*) DELTA_R
radius = RADIUS_INITIAL
Do while (radius .le. MAX_RADIUS)
Write(*,*) 'radius:', radius
area =S(radius)
volume=V(radius)
Write(*,*) ' area =',area,' volume =',volume
Write(*,*)
radius = radius + DELTA_R
End do
Stop
End
のように、外部関数を使う。FUNCTION 文は、メインプログラムの後ろにつけて、コン
パイルするのが良いだろう
。
浦 昭二: FORTRAN入門(3訂版)(培風館)
森口繁一:JIS FORTRAN入門(第3版)上・下 (東大出版会)