はじめに
大気科学や海洋学や惑星科学などの地球物理学分野では、現代でもFortranが主流です。自分も研究で使用するため、いつでも確認できるように自分用のまとめ記事を書きました。とりあえず暗黙の型宣言を無効にしておきましょう。
program main
implicit none
end program main
目次
- 基礎文法
- 型宣言
- 制御構文
- 入出力
- サブプログラム
- コンパイルと実行
注:これまで学んだ知識はFORTRAN77とFortran90/95の両方が混ざっているので、いくつかFortran90/95に当てはまらないものがあるかもしれません。
1. 基礎文法
- 添字は1スタート
- コメントアウトは
!
(77で使用されていたC
も可) - 文字列は
"Hello"
と'Hello'
どちらでもよい - 1行に書ける文字数は132文字
- コード中の改行は
&
implicit noneについて
おまじない
iからnまでの英字を型名に指定すると、自動的に整数として扱われます。これは暗黙の型宣言と呼ばれます。思わぬエラーの原因にもなるので、implicit none
で無効にし、自分で型宣言を行います。
例:ローレンツ・アトラクタの簡易式
!ここはコメント
!Does the Flap of a Butterfly's Wings in Brazil Set Off a Tornado in Texas?
program lorenz
!おまじない
implicit none
!型宣言
real(8) :: x,y,z
real(8) :: dx,dy,dz
integer(4) :: i,n
!初期値の入力
write(6,*) 'Plese enter x0, y0, z0'
read(5,*) x, y, z
!試行回数の入力
write(6,*) 'Plese enter Number'
read(5,*) n
!n単位時間進んだ時の値
!dx/dt=-10x+10y, dy/dt=-xz+28x-y, dz/dt=xy-8x/3
do i = 1,n
dx = x - x*10 + y*10
dy = y - x*z + x*28 - y
dz = z + x*y - z*8/3
x=dx
y=dy
z=dz
end do
print *, x, y, z
stop
end program lorenz
2. 型宣言
Fortranは最初に変数・定数・配列等を全て指定する必要があります。
- 大文字と小文字は区別しない(
ans
とANS
は併用できない) - 先頭の文字に数字は使用できない
-
-
と.
は使用できない
変数・定数
デフォルトでreal
、integer
は4バイトです。4バイトは単精度、8バイトは倍精度と呼ばれています。宣言した型から変更することもできますが、後から倍精度にする場合には精度が落ちます。
!型を宣言する
integer :: a,b !整数
real :: x !実数
complex :: c !複素数
logical :: ans !論理(.true.と.false.)
double precision :: d !倍精度実数(real(8)と同意)
character(len=10) :: s !長さ10の文字列(指定しない場合は1)
!初期値を指定する
integer :: a=5,b=-1
real :: x=2.5
complex :: c=(1.3,0.5) !c=1.3+0.5i
logical :: ans=.true.
!データ領域の大きさを指定する
real(4) :: m !4バイト(単精度)
real(8) :: n !8バイト(倍精度)
!異なるコンパイラを用いるならkindパラメータが必要(本記事では省略)
real(kind=4) :: m
!定数の場合はparameterを追加する
integer(4),parameter :: days=365
配列
型名,dimension(要素数) :: 配列名
もしくは 型名 :: 配列名(要素数)
!配列を宣言する
!どちらの書き方も同じ
integer(4),dimension(5) :: A
integer(4) :: A(5)
!添字を[0 - 4]にする(デフォルトは1-5)
integer(4),dimension(0:4) :: A
integer(4) :: A(0:4)
!配列の初期化
integer,dimension(5) :: A = (/1,3,5,7,9/)
!全ての要素を9にする
A(:) = 9.0
!3×5の二次元配列
real(8),dimension(3,5) :: A
real(8) :: A(3,5)
!3×3×2の三次元配列
real(8),dimension(3,3,2) :: A
real(8) :: A(3,3,2)
動的配列
大きさがnの配列を作成する場合、real :: A(n)
と書くことはできない。
配列のサイズが不明である場合は、allocatable
属性を付与してあげることで、配列用のメモリを確保することができます。配列を使用する際にはallocate
関数を用いてメモリを割り付けます。
使用後はメモリを解放してあげる必要があります。
real :: x,y
x=3*5
y=20
!動的配列の宣言
!どちらの書き方も同じ
real(8),allocatable,dimension(:) ::A
real(8),allocatable :: A(:)
!二次元配列
real(8),allocatable,dimension(:,:) :: B
!メモリの割り当て
allocate(A(100))
!x×yの二次元配列
allocate(B(1:x,1:y))
!メモリの解放を忘れずに
deallocate(A)
deallocate(B)
四則演算・組み込み関数
abs(x) !絶対値
sqrt(x) !平方根
mod(x,y) !あまり
exp(x) !指数
log(x) !自然対数
max(a,b,c) !最大値
min(a,b,c) !最小値
sin(x) !正弦
cos(x) !余弦
tan(x) !正接
asin(x) !逆正弦
acos(x) !逆余弦
atan(x) !逆正接
!pi=4*atan(1.0)=3.1415...
3. 制御構文
doループ
do 変数 = start,end,(刻み値)
end do
doループの変数は整数型(integer
)でないとエラーになります。
この変数は別のループでも再利用できます。
ループを抜ける時はexit
、ループの最初に戻るときはcycle
を使います。
integer(4) :: i,ans
do i = 1,5
ans = ans+i
end do
print *, ans !ans=15
if文
if (条件式) then
else if (条件式) then
else
end if
integer(4) :: x
if(x==0) then
print *, "Zero"
else if(mod(x,2)==0) then
print *, "Even number"
else
print *, "Odd number"
end if
比較演算子
意味 | 演算子 | 意味 | 演算子 |
---|---|---|---|
大きい | > | 小さい | < |
以上 | >= | 以下 | <= |
等しい | == | 等しくない | /= |
論理演算子
意味 | 演算子 |
---|---|
否定 | .not. x<y |
かつ | x>0 .and. y>0 |
もしくは | x>0 .or. y>0 |
while
do while(条件式)
end do
!2の何乗か調べる
integer(4) a=512,n=0
do while(a<=1)
a=a/2
n=n+1
end do
4. 入出力
ファイルの読み書きの大まかな流れです。
- openでファイルを開く
- readでファイルを読む
- 読み取ったデータを操作する
- writeでデータを出力する
!hoge.txt={70,55,89,62,91}
program score
implicit none
integer :: i
integer,dimension(5) :: x
open(10,file='hoge.txt',action=read)
do i = 1,5
read (10,*) x(i)
write (6,*) x(i)
end do
print *, 'all finishd!'
close(10)
end program score
open
open(unit=10, file='hoge.txt', action='read',status='replace')
!(処理)
close (10)
openしたら忘れずにclose 装置番号
しましょう。
引数 | 説明 | デフォルト値 |
---|---|---|
unit | 装置番号。5が標準入力で6が標準出力。開いたファイルの便宜上の名前付けであり、複数のファイルを扱う際はそれぞれ別の数字にする必要がある。"unit="は省略可。 | |
file | ファイル名 | |
action | 読み取り専用ならread、書き込み専用ならwrite、読み書きどちらもならreadwrite。 | readwrite |
form | アスキー形式ならformatted、バイナリ形式ならunformatted。 | formatted |
status | 新規ファイルを作成するならnew。既存ファイルを使用するならold。同名ファイルが存在した場合上書きするならreplace。ファイルの存在の有無を問わないならunknownd。 | unknownd |
recl | レコードの長さ | |
iostat | 設定した変数に、ファイルが正常に開けた場合0を、そうでない場合には0以外を返す |
read・write・print
read(装置番号,書式) 値
とwrite(装置番号,書式) 値
アスタリスクは、前半部分が装置番号(unit)を、後半部分が書式(form)を指しています。printは画面へのみ出力可能です。
装置番号と書式について
装置番号:装置番号は標準入力が5、標準出力が6です。デフォルト値で画面への入出力になります。ファイルに入出力する場合、open文で指定した装置番号のファイルが使用されます。書式:( )
で囲って指定します。桁数を揃えて出力することができるため、例えばバイナリデータとして扱うことが出来るようになります。書式を空にしたままreadすると読み込まれません(行を読み飛ばすことが出来る)。
形式 | 説明 | 例 |
---|---|---|
I | 整数で桁数を合わせる | I4 |
F | 少数で桁数を合わせる | F3.2 |
chalactar(20) :: name
!標準入力
read(5,*) name !pochi
!標準出力
write(6,*) "Hello ", name, "!"
! Hello pochi!
!print文
print*, "Hello Fortran!"
! Hello Fortran!
バイナリデータを扱う場合
バイナリ形式を扱う場合は、書式がないので指定しない(アスタリスク不要)。direct accessなら必ずreclも指定する。また、Fortranでは通常1数字4バイトなので、配列を倍精度にするとエラーになります。
!格子点が365×30のデータ(バイナリ形式)
real(4),dimension(365:30) :: data
open(11,file="hoge.bin", action='read', form='unformatted', &
& access='direct',recl=365*30)
read(11)
5. サブプログラム
メインプログラムとサブプログラムの名前は別にする必要があります。メインプログラムに値を返す場合は関数、返さない場合はサブルーチンを用います。intent(IN)
と追記すると入力専用の値として受け取られるため、変更を防ぐことが出来ます。
サブルーチン
メインプログラムに値を返しません。call(引数)
で呼び出すことが出来ます。
!バブルソート
program sort
implicit none
integer(4) :: i,n
integer(4) :: A(5)=(/3,1,4,2,5/)
n=5
call b_sort(n,A)
stop
contains
!ここからサブルーチン
subroutine b_sort(n,A)
implicit none
integer(4),intent(IN) :: n
integer(4) :: A(n)
integer(4) :: i,j,k
do i = 1,n-1
do j = i+1,n
if(A(j)<=A(i)) then
k=A(j)
A(j)=A(i)
A(i)=k
end if
end do
print *, A(1),A(2),A(3),A(4),A(5)
end do
return
end subroutine b_sort
end program sort
!---------------------------result---------------------------
! 1 3 4 2 5
! 1 2 4 3 5
! 1 2 3 4 5
! 1 2 3 4 5
関数
メインプログラムに値を1つ返します。
!最大公約数と最小公倍数を求める
program gcd_lcm
implicit none
integer :: a,b
print *, "Enter number"
read(5,*) a,b
write(6,*) "GCD=",gcd(a,b)," LCM=",a*b/(gcd(a,b))
stop
contains
!ここから関数
integer function gcd(a,b)
implicit none
integer, intent(IN) :: a,b
integer :: aa,bb,tmp
aa=a
bb=b
do
tmp=mod(aa,bb)
if(tmp==0) exit
aa=bb
bb=tmp
end do
gcd = bb
return
end function gcd
end program gcd_lcm
6. コンパイルと実行
gfortranでコンパイルしています。成功すればa.outという名前の実行ファイルが作成されます。
gfortran hoge.f90
./a.out
#実行ファイルの名前を指定してコンパイル
gfortran hoge.f90 -o hogehoge
./hogehoge
おわりに
Fortranとはまだまだ長い付き合いになりそうなので、もっと勉強してもっと仲良くなれればいいなと思っています。