この文書の現在のバージョンと選択したバージョンの差分を表示します。
次のリビジョン | 前のリビジョン | ||
fortran:tips [2013/12/22 18:28] saito created |
fortran:tips [2017/10/03 12:55] (現在) |
||
---|---|---|---|
ライン 1: | ライン 1: | ||
====== tips ====== | ====== tips ====== | ||
+ | * intelのコンパイラは[[fortran:ifort]]参照のこと. | ||
+ | * [[http://www.owlnet.rice.edu/~ceng303/manuals/fortran/]] が役に立ちそう. | ||
+ | * | ||
+ | ===== よくある間違い ===== | ||
+ | コーディングにおいてよくある間違いをまとめる. | ||
+ | |||
+ | ==== べき乗の順序 ==== | ||
+ | <nowiki>計算の優先順位は | ||
+ | +- < */ < ** | ||
+ | である.</nowiki> | ||
+ | <code fortran> | ||
+ | print*,-1**0 | ||
+ | </code> | ||
+ | <nowiki> | ||
+ | これは-(1**0)と解釈されるので,出力結果は−1. | ||
+ | -1に対してべき乗する場合は,(-1)**0. | ||
+ | </nowiki> | ||
+ | |||
+ | ==== 論理演算の順序 ==== | ||
+ | <nowiki> | ||
+ | 論理演算子の優先順位は | ||
+ | .eqv., .neqv. < .or. < .and. < .not. | ||
+ | である. | ||
+ | </nowiki> | ||
+ | <code fortran> | ||
+ | logical :: a=.false. | ||
+ | num :: i=1 | ||
+ | if(a.eqv..false..or.i==1) then | ||
+ | print*,'if' | ||
+ | else | ||
+ | print*,'else' | ||
+ | end if | ||
+ | </code><nowiki> | ||
+ | これは,a.eqv.(.false..or.i==1) と解釈される. | ||
+ | (.false..or.i==1) はtrueなので,上のコードはelseを吐き出す. | ||
+ | 前後の条件をorでつなぐ場合は, | ||
+ | if((a.eqv..false.).or.(i==1)) としてカッコで順序を明示する. | ||
+ | </nowiki> | ||
+ | |||
+ | ちなみに | ||
+ | * (.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 | ||
+ | <code fortran> | ||
+ | if (allocated(x).eqv..false.) allocate(x(n)) | ||
+ | </code> | ||
+ | ===== construct name ===== | ||
+ | 入れ子のループで,cycleやexitを使って外側に飛びたいときは,do ループにラベルをつける. | ||
+ | これで文番号を付けずに好きなところへ飛べる. | ||
+ | - do の前にラベルとコロンをつける. | ||
+ | - cycleやexitの後にラベルをつける. | ||
+ | - end do の後ろにラベルをつける. | ||
+ | 例 | ||
+ | <code fortran> | ||
+ | outer : do i=1,n | ||
+ | do j=1,n | ||
+ | if(...) cycle outer | ||
+ | end do | ||
+ | end do outer | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ===== 読み込み専用,書き込み専用で開く ===== | ||
+ | 読み込み専用で開く場合. | ||
+ | <code fortran> | ||
+ | open(10,file='input.dat',action='read') | ||
+ | </code> | ||
+ | その他,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| | ||
+ | |||
+ | 例えば以下のようにする. | ||
+ | <code bash> | ||
+ | gfortran filename.f90 -O2 -stand f03 -assume realloc_lhs -check all -traceback -warn all -fstack-protector -assume protect_parens -implicitnone | ||
+ | </code> | ||
+ | ===== 連番のファイル名をつける。 ===== | ||
+ | ファイル名をcharacter変数に代入して使う。ファイル名の変更にはwrite文を使う。 | ||
+ | 逐次計算に使える。 | ||
+ | <code fortran> | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | 処理は[[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に以下のように修正. | ||
+ | <code python> | ||
+ | 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))) | ||
+ | </code> | ||
+ | |||
+ | 以下,Makefile のサンプル. | ||
+ | <code bash> | ||
+ | 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} | ||
+ | </code> | ||
+ | |||
+ | ===== makefileでコンパイル ===== | ||
+ | 複数のファイル(サブルーチンetc.)で構成されるプログラムを動かすのに便利. | ||
+ | 以下の文を「makefile」という名前で作り,コンパイルしたいファイルと同じディレクトリに置く. | ||
+ | (以下,main.f90, modules.f90[モジュールファイル], sub1.f90, sub2.f90をコンパイルする場合) | ||
+ | <code> | ||
+ | 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} | ||
+ | </code> | ||
+ | あとは,makeコマンドを打てばコンパイル完了.そして実行(上の例では./a.outを打てば良い). | ||
+ | <code> | ||
+ | $ make | ||
+ | $./a.out | ||
+ | </code> | ||
+ | また,以下の様にmake cleanで実行ファイル(a.out)及びオブジェクトファイル(*.o)を消去できる. | ||
+ | <code> | ||
+ | $ make clean | ||
+ | </code> | ||
+ | 以下,makefileの変数について簡単に説明する. | ||
+ | <code> | ||
+ | TARGET = 実行ファイル名 | ||
+ | OBJECTS = モジュールファイル プログラムファイル (すべて拡張子は.oとする.) | ||
+ | F90 = コンパイラコマンド (gfortranを使うなら「gfortran」) | ||
+ | FLAGS = コンパイラオプション | ||
+ | COMMON_MOD = モジュールファイル (拡張子は.f90) | ||
+ | </code> | ||
+ | |||
+ | ===== 何行あるか分からないときのデータファイルの読み込み ===== | ||
+ | |||
+ | データファイルの中に何行あるか分からないときにはiostatかendを使う. | ||
+ | iostatの方がスマートなやり方かも. | ||
+ | |||
+ | ==== やり方その1 ==== | ||
+ | read文にiostatのオプションを付ける. | ||
+ | iostatが正の数を返す場合はエラー,負の値を返す場合は行の終わりを意味するらしい. | ||
+ | <code fortran> | ||
+ | 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 | ||
+ | </code> | ||
+ | ==== やり方その2 ==== | ||
+ | |||
+ | endを使う. | ||
+ | |||
+ | 以下サンプル.プログラムの中では10回ループを回すが,読み込むのは5行分だけ. | ||
+ | |||
+ | <code bash> | ||
+ | gfortran hoge.f90 | ||
+ | ./a.out < hoge.dat | ||
+ | </code> | ||
+ | |||
+ | hoge.f90 | ||
+ | <code fortran> | ||
+ | program hoge | ||
+ | do i=1,10 | ||
+ | read(*,*,end=999) a,b | ||
+ | write(*,*) a**2-b | ||
+ | end do | ||
+ | 999 continue | ||
+ | end program hoge | ||
+ | </code> | ||
+ | |||
+ | hoge.dat | ||
+ | <code> | ||
+ | 1. 1. | ||
+ | 2. 4. | ||
+ | 3. 9. | ||
+ | 4. 16. | ||
+ | 5. 25. | ||
+ | </code> | ||
+ | |||
+ | ===== NaNの検出 ===== | ||
+ | |||
+ | |||
+ | 浮動小数点演算例外を検出するコンパイラオプションがあるので、それを使用する。 | ||
+ | |||
+ | ===== Makefile ===== | ||
+ | 保存するためのmakefile | ||
+ | <code bash> | ||
+ | DATE= `date +%y%m%d%H%M` | ||
+ | TAR = backup/backup${DATE}.tgz | ||
+ | backup : | ||
+ | tar czvf ${TAR} Makefile *.f90 | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ===== implicit none ===== | ||
+ | 宣言文で宣言した変数以外を利用しないようにする。 | ||
+ | 長いプログラムを書く場合はミスを避けるためにも使用するべき。 | ||
+ | 自由形式の場合はuse文の後に使用。 | ||
+ | <code fortran> | ||
+ | program hoge | ||
+ | use hoge_lib | ||
+ | implicit none | ||
+ | real(8) a,b,c, | ||
+ | ... | ||
+ | </code> | ||
+ | ===== 装置番号 ===== | ||
+ | write(?,*)やread(?,*)の?に入る番号。 | ||
+ | 通常、5が標準入力(キーボード)、6が標準出力(ディスプレイ上の端末)に使用されるので、 | ||
+ | 5と6を使ってopenするのは避けるべき。 | ||
+ | slatecのI1MACHを使えば、標準入力、標準出力の番号が調べられる。 | ||
+ | 装置番号にはcharacterも入る。 | ||
+ | |||
+ | |||
+ | |||
+ | ===== 連番のファイル名をつける。 ===== | ||
+ | ファイル名をcharacter変数に代入して使う。ファイル名の変更にはwrite文を使う。 | ||
+ | 逐次計算に使える。 | ||
+ | <code fortran> | ||
+ | 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 | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ | ===== 簡単なシェルスクリプト ===== | ||
+ | 連続してプログラムを実行したいとき、shファイルが便利。 | ||
+ | 端末で入力する内容をあらかじめファイルに書いておき、それを実行すれば、上から順に実行してくれる。 | ||
+ | windowsで言うバッチファイル。 | ||
+ | |||
+ | <code bash> | ||
+ | gfortran hoge.f90 | ||
+ | cd case10 | ||
+ | ../a.out | ||
+ | cd ../case20 | ||
+ | ../a.out | ||
+ | cd ../case30 | ||
+ | ../a.out | ||
+ | </code> | ||
+ | <code> | ||
+ | $ sh hoge.sh | ||
+ | </code> |