====== tips ======
* intelのコンパイラは[[fortran:ifort]]参照のこと.
* [[http://www.owlnet.rice.edu/~ceng303/manuals/fortran/]] が役に立ちそう.
*
===== よくある間違い =====
コーディングにおいてよくある間違いをまとめる.
==== べき乗の順序 ====
計算の優先順位は
+- < */ < **
である.
print*,-1**0
これは-(1**0)と解釈されるので,出力結果は−1.
-1に対してべき乗する場合は,(-1)**0.
==== 論理演算の順序 ====
論理演算子の優先順位は
.eqv., .neqv. < .or. < .and. < .not.
である.
logical :: a=.false.
num :: i=1
if(a.eqv..false..or.i==1) then
print*,'if'
else
print*,'else'
end if
これは,a.eqv.(.false..or.i==1) と解釈される.
(.false..or.i==1) はtrueなので,上のコードはelseを吐き出す.
前後の条件をorでつなぐ場合は,
if((a.eqv..false.).or.(i==1)) としてカッコで順序を明示する.
ちなみに
* (.ture..or..false.)は.true.(どちらかが真なのでtrue)
* (.ture..and..false.)は.false.(どちらも真でないのでfalse)
になる.
===== allocated =====
すでにallocateしたかどうかわからない時は,allocatedで確かめてからallocateする.
https://gcc.gnu.org/onlinedocs/gcc-4.1.0/gfortran/ALLOCATED.html
if (allocated(x).eqv..false.) allocate(x(n))
===== construct name =====
入れ子のループで,cycleやexitを使って外側に飛びたいときは,do ループにラベルをつける.
これで文番号を付けずに好きなところへ飛べる.
- do の前にラベルとコロンをつける.
- cycleやexitの後にラベルをつける.
- end do の後ろにラベルをつける.
例
outer : do i=1,n
do j=1,n
if(...) cycle outer
end do
end do outer
===== 読み込み専用,書き込み専用で開く =====
読み込み専用で開く場合.
open(10,file='input.dat',action='read')
その他,action='write', action='readwrite'もある.
===== コンパイラオプション =====
* プログラム作成段階においては,配列外参照,暗黙の型宣言,浮動小数点演算例外の検出はつけてコンパイルした方が良い.
* プログラムが完成して,エラーがない場合には以下のコンパイルオプションはない方が良い.ない方が早く計算できる.
^ compiler ^ gfortran ^ ifort ^
|エラーの検出FIXME|-Wall|-check all|
|配列外参照|-fbounds-check|-CB|
|暗黙の型宣言|-fimplicit-none|-warn declarations|
|浮動小数点演算例外の検出|-ffpe-trap=zero|-fpe0|
|標準外機能の警告|-std=f95|-std|
例えば以下のようにする.
gfortran filename.f90 -O2 -stand f03 -assume realloc_lhs -check all -traceback -warn all -fstack-protector -assume protect_parens -implicitnone
===== 連番のファイル名をつける。 =====
ファイル名をcharacter変数に代入して使う。ファイル名の変更にはwrite文を使う。
逐次計算に使える。
character(len=12) filename
...
do i=1,100
...
write(filename,'(a,i4.4,a)') 'hoge',i,'.dat'
open(10,file=filename)
...
write(10,*) ...
...
close(10)
end do
処理は[[movie]]参照のこと.
===== makefileでコンパイル その2=====
以下の記事は古い.[[fortran:makefile|別のページ]]を参照せよ.
moduleファイルを含む場合,依存関係をはっきりさせる必要がある.
依存関係を変えるたびにmakeファイルを書き変えるのは面倒なので,依存関係を見てくれる
f90_mod_deps.py を使う.
http://lagrange.mechse.illinois.edu/mwest/f90_mod_deps/
コンパイル不要のpardisoやompのモジュールを読み込んだり,同一ファイル内に複数のモジュールが存在し循環参照が起きる場合は,f90_mod_deps.py のwrite_depsに以下のように修正.
def write_deps(outf, filename, deps, mods):
filebase, fileext = os.path.splitext(filename)
#>>>
loadmod="MKL_PARDISO.mod"
if loadmod in deps:
deps.remove(loadmod)
loadmod="omp_lib.mod"
if loadmod in deps:
deps.remove(loadmod)
#<<<
outf.write("%s.o: %s\n" % (filebase, " ".join(deps)))
for mod in mods:
#>>>
if mod in deps:
deps.remove(mod)
#<<<
outf.write("%s: %s\n"
% (mod, " ".join(deps)))
以下,Makefile のサンプル.
TARGET = a.out
DEPS=hoge.deps
OBJECTS = piyo.o foo.o bar.o main.o
F90 = gfortran
FFLAGS=-Wall -ffpe-trap=invalid,zero,overflow,underflow -fbounds-check -fimplicit-none -fbacktrace -fopenmp
#FFLAGS=-O3 -fopenmp
#F90 = ifort
#FFLAGS=-check all -warn all -std -gen_interfaces -fpe0 -ftrapuv -traceback
#FFLAGS = -mkl -O3
SOURCES=$(OBJECTS:.o=.f90)
.SUFFIXES :
.SUFFIXES : .o .f90 .f
.f.o:
${F90} -c $< ${FFLAGS}
.f90.o:
${F90} -c $< ${FFLAGS}
.PHONY:all
all: ${DEPS} ${TARGET}
${DEPS}: ${SOURCES}
python f90_mod_deps.py --output $@ $^
${TARGET} : ${OBJECTS}
${F90} -o $@ $^ ${FFLAGS}
-include ${DEPS}
%.o %.mod: %.f90
${F90} -c $< ${FFLAGS}
touch $(patsubst %.f90,%.mod,$<)
clean :
rm ${TARGET} *.mod *.f90~ ${OBJECTS}
===== makefileでコンパイル =====
複数のファイル(サブルーチンetc.)で構成されるプログラムを動かすのに便利.
以下の文を「makefile」という名前で作り,コンパイルしたいファイルと同じディレクトリに置く.
(以下,main.f90, modules.f90[モジュールファイル], sub1.f90, sub2.f90をコンパイルする場合)
TARGET = a.out
OBJECTS = modules.o main.o sub1.o sub2.o
F90 = ifort
FLAGS = -check all -warn declarations -CB -fpe0 -traceback
COMMON_MOD = modules.f90
.SUFFIXES :
.SUFFIXES : .o .f90
.f90.o:
${F90} -c $< ${FFLAGS}
${TARGET} : ${OBJECTS}
${F90} -o $@ ${OBJECTS}
clean :
rm *.o ${TARGET} *.mod
${OBJECTS} : ${COMMON_MOD}
あとは,makeコマンドを打てばコンパイル完了.そして実行(上の例では./a.outを打てば良い).
$ make
$./a.out
また,以下の様にmake cleanで実行ファイル(a.out)及びオブジェクトファイル(*.o)を消去できる.
$ make clean
以下,makefileの変数について簡単に説明する.
TARGET = 実行ファイル名
OBJECTS = モジュールファイル プログラムファイル (すべて拡張子は.oとする.)
F90 = コンパイラコマンド (gfortranを使うなら「gfortran」)
FLAGS = コンパイラオプション
COMMON_MOD = モジュールファイル (拡張子は.f90)
===== 何行あるか分からないときのデータファイルの読み込み =====
データファイルの中に何行あるか分からないときにはiostatかendを使う.
iostatの方がスマートなやり方かも.
==== やり方その1 ====
read文にiostatのオプションを付ける.
iostatが正の数を返す場合はエラー,負の値を返す場合は行の終わりを意味するらしい.
program hoge
implicit none
real a,b
integer i,inputstatus
do i=1,10
read(*,*,iostat=inputstatus) a,b
if(inputstatus>0) stop "error"
if(inputstatus<0) exit
write(*,*) a,b,a**2-b
end do
end program hoge
==== やり方その2 ====
endを使う.
以下サンプル.プログラムの中では10回ループを回すが,読み込むのは5行分だけ.
gfortran hoge.f90
./a.out < hoge.dat
hoge.f90
program hoge
do i=1,10
read(*,*,end=999) a,b
write(*,*) a**2-b
end do
999 continue
end program hoge
hoge.dat
1. 1.
2. 4.
3. 9.
4. 16.
5. 25.
===== NaNの検出 =====
浮動小数点演算例外を検出するコンパイラオプションがあるので、それを使用する。
===== Makefile =====
保存するためのmakefile
DATE= `date +%y%m%d%H%M`
TAR = backup/backup${DATE}.tgz
backup :
tar czvf ${TAR} Makefile *.f90
===== implicit none =====
宣言文で宣言した変数以外を利用しないようにする。
長いプログラムを書く場合はミスを避けるためにも使用するべき。
自由形式の場合はuse文の後に使用。
program hoge
use hoge_lib
implicit none
real(8) a,b,c,
...
===== 装置番号 =====
write(?,*)やread(?,*)の?に入る番号。
通常、5が標準入力(キーボード)、6が標準出力(ディスプレイ上の端末)に使用されるので、
5と6を使ってopenするのは避けるべき。
slatecのI1MACHを使えば、標準入力、標準出力の番号が調べられる。
装置番号にはcharacterも入る。
===== 連番のファイル名をつける。 =====
ファイル名をcharacter変数に代入して使う。ファイル名の変更にはwrite文を使う。
逐次計算に使える。
character(len=12) filename
...
do i=1,100
write(filename,'(a,i4.4,a)') 'hoge',i,'.dat'
open(10,file=filename)
...
write(10,*) ...
...
close(10)
end do
===== 簡単なシェルスクリプト =====
連続してプログラムを実行したいとき、shファイルが便利。
端末で入力する内容をあらかじめファイルに書いておき、それを実行すれば、上から順に実行してくれる。
windowsで言うバッチファイル。
gfortran hoge.f90
cd case10
../a.out
cd ../case20
../a.out
cd ../case30
../a.out
$ sh hoge.sh