プログラミング苦手な上に、Fortran太古の言語とか言われてるけど、研究で必要なので備忘録。。。
これだけ覚えれば、あとは実際のコード見ながらでもなんとか読めるでしょうという程度まで。
簡単な順に書いているわけではないので、初心者は2周読めば理解できるかも。
コーディングする際は別記事Fortran備忘録(2) 用途別Fortran90/95基本メモ参照。
環境構築とコンパイル
Macなのでコンパイラのgfortranが内包されたgccをHomebrew環境下でインストール
brew install gcc #インストール
which gfortran #gfortranのパス確認
gfortran -v #バージョン確認
program hello
print *, 'Hello, world!'
end program hello
gfortran hello.f90 -o hello.out
./hello.out
テキストファイルへの出力リダイレクトを行う場合、
gfortran hello.f90 -o hello.out
./hello.out > output.txt
Hello, world!
モジュールなどの副プログラムを使用しているコードを実行する場合、
gfortran mod_params.F90 mod_one.F90 mod_two.F90 main.F90 -o main.out
とするか、あるいは、以下のようにオブジェクトファイルを作る。
gfortran -c mod_params.F90
gfortran -c mod_one.F90
gfortran -c mod_two.F90
gfortran -c main.F90
gfortran mod_one.o mod_two.o main.o -o main.out
※よく使うgfortranのデバッグオプション
オプション | 意味 |
---|---|
-c | オブジェクトファイルの生成 |
-O2 | (main.F90 の直後に置いて)最適化 |
-fbounds-check | 配列の領域外からの参照を検出 |
ルール
- Fortran90/95であることを明らかにするため、
.f
より.f90
を使うのが慣例。(自由形式のFortran90/95コードでも.f90
がよく使われるっぽい(?)プリプロセッサを使う際は.F90
と大文字にする!(用途別Fortran90/95基本メモ参照)) - 必ず宣言部→実行部→副プログラム部の順で書く。(実行部の中で宣言できない。)
- プログラムは
end
で終える。 - program文は省略可能。
- コメントアウトは
!
(行頭、行末)、またはFortran77のみ(?)行頭にc
。コメント内日本語ok。 - 大文字小文字の区別が無いので、
SUBROUTINE
とかCONTAINS
とか、区切りを大文字にしておくと見やすい。 - プログラム名と同じ変数名は良くない。
- f95の自由形式に対応しているコンパイラがほとんどなので一行の文字数問題は気にしなくていい。(132文字まで)規定文字数を超えると書いてあっても無視される。
- 一行を分ける時は一行目の最後に
&
。(文字列中で改行もでき、その時は一行目末に加え、二行目の最初にもスペース入れずに&
を入れる。) - **
implicit none
を必ず宣言する。**外すと暗黙の型規約が適用され、i~nが整数、他が実数になるらしい。
制御構造(と簡単なサンプルコード)
反復のdoループ
do i = 1, 100
sum = sum + i
enddo
全体
PROGRAM do_loop
implicit none
integer :: i, sum
sum = 0
do i = 1, 100 !
sum = sum + i !
enddo !
write(*, *) 'sum = ', sum
END PROGRAM do_loop
後判定のdo while
構文もある。
条件分岐のif
if (i == 0) then
write(*,*) i, "は0です。"
else if (i < 0) then
write(*,*) i, "は負です。"
else if (mod(i,2) == 0) then
write(*,*) i, "は偶数です。"
else
write(*,*) i, "は奇数です。"
end if
全体
PROGRAM if_oddeven
implicit none
integer :: i
print *, "整数を入力:"
read(*,*) i
if (i == 0) then
write(*,*) i, "は0です。"
else if (i < 0) then
write(*,*) i, "は負です。"
else if (mod(i,2) == 0) then
write(*,*) i, "は偶数です。"
else
write(*,*) i, "は奇数です。"
end if
END PROGRAM if_oddeven
then
必須。
ケース分岐のselect
構文もある。
※比較演算子の別表記
どっちも使える。
意味 | よくあるやつ | ドットと文字 |
---|---|---|
Equal | x == y |
x .eq. y |
Not Equal | x /= y |
x .ne. y |
Greater Than | x > y |
x .gt. y |
Greater than or Equal | x >= y |
'x .ge. y` |
Less Than | x < y |
x .lt. y |
Less than or Equal | x <= y |
x .le. y |
not equalは!=
じゃなくて、/=
なことに注意!
論理演算子
[否定] .not.
を使う。
[かつ、または] Fortranに&&
や||
はない!.and.
や.or.
を使う。
[論理値の比較].eqv.``.neqv
もある。
##宣言と型
型
- 数値型
- 整数型
- 基本整数型
integer
- 基本整数型
- 実数型
real(8)
- 複素数型
- 整数型
- 文字型
- 論理型
logical
- 論理定数
.true.
あるいは.false.
を持つ。(が、表示される時はT
とF
。)
- 論理定数
宣言
implicit none
real(8) :: real_variable
real(8), parameter :: pi = 3.14159265359d0
real(8), allocatable :: real_number_data(:)
::
はあるに越したことはないっぽい。
allocatable
parameter
allocate(real_number_data(number_of_data))
save属性の局所変数は複数回の副プログラム呼び出しに対して値を保持する。
(saveが付いていなくてもFortranでは初期化(宣言と代入が同一文で行われる)時に自動的にsave属性が付く)(厄介)
SUBROUTINE glob
integer, save :: global_variable = 5
END SUBROUTINE glob
入出力
標準入出力(ディスプレイへの入出力)
!入力
read(*,*) x, y, z
!出力
print *, 'sum =', sum, 'dayo!'
write(*,*) 'sum =', sum, 'dayo!'
入力はread
を使えば、ターミナルで変数の入力を求められるようになる。(print *, 'x=?'
などとしておく。)
出力は普通print
かwrite
を用いる。
read(*,*)
やwrite(*,*)
の*
は出力先、書式を決める装置番号や編集記述子(printの*
も)というものだが、どちらも標準として(*,*)
。
print
は後ろにカンマがいる。
出力するものは、sum
などの変数でも'sum = '
などの文字列でもok。
ファイル入出力と開閉
##関数、サブルーチン、モジュールの違いと使い方
関数は返り値がある。
サブルーチンは返り値がない。(他言語でいうvoid
型関数。)
モジュールはサブルーチンや関数をまとめたもの。
関数(function)
後述するサブルーチンとは違って、使用時CALL
する必要はない。
仮引数には以下のintent属性を付けることが必須。(ローカル変数には不要。)
属性 | 実引数からの値の受け取り | 値の演算・代入と保持 |
---|---|---|
intent(in) |
○ | × |
intent(out) |
× | ○ |
intent(inout) |
○ | ○ |
要は、関数・サブルーチンを使うときに引数に入れる値が決まっている場合はintent(in)
、
関数・サブルーチン中で仮引数の値が代入される場合はintent(out)
。
サブルーチン(subroutine)
個人的に「手続」っていうイメージ。
他言語でいうvoid
型関数。
使用時はCALL name_of_subroutine(arg)
で呼び出す。
主プログラム内でCALL
の行に辿り着くと、副プログラムの一行目から最後まで演算が行われ、主プログラムの次の行に移る。副プログラムの演算を途中で抜け出したい時はreturn
。
冒頭でサブルーチンには返り値がないと言っているが、intent(out)
を用いて値を計算・代入することは可能であり、実際二つ以上の値を返したい場合はサブルーチンが用いられる。
モジュール(module)
使う時はUSE name_of_module
で呼び出す。
USE
宣言はimplicit none
より前。
モジュール内のサブルーチンを呼び出す時は、USE
宣言した後にCALL name_of_subroutine(arg)
。
Fortranでグローバル変数を用いる際はsave
などもあるが、一般にmod_params.F90
などのモジュールを作り、その中に宣言するのが通例。
プログラム単位と副プログラムについて
ファイル分割が許される最小単位
- 主プログラム(program 〜 end program )
- 外部副プログラム(containされない関数、サブルーチン)
- モジュール
- block data
の4種類。以下で一つずつ説明。
副プログラムとは、関数あるいはサブルーチンのこと。
以下のように、副プログラムは内部副プログラム、外部副プログラム、モジュール副プログラムの3種類。
主プログラム(main program)
内部副プログラムは主プログラム内に含まれる(containされる)関数、サブルーチン。主プログラム内でしか使えないから、機能拡張に向かない。外部副プログラムでいい。
PROGRAM name_of_program
!宣言部
!実行部
CONTAINS
!内部副プログラム(internal subprogram)1
!内部副プログラム(internal subprogram)2
!...
END PROGRAM name_of_program
外部副プログラム(external subprogram)
反対に、主プログラム内に含まれない(containされない)関数、サブルーチン。
FUNCTION name_of_function(arg)
!宣言部
!実行部
CONTAINS
!内部副プログラム
END FUNCTION name_of_function
SUBROUTINE name_of_subroutine(arg)
!宣言部
!実行部
CONTAINS
!内部副プログラム
END SUBROUTINE name_of_subroutine
モジュール(module)
MODULE NAME_OF_MODULE
!...
CONTAINS
!モジュール副プログラム(この中にさらに内部副プログラムを入れることは可能。)
END MODULE NAME_OF_MODULE
block data
宣言部だけでファイルを作るという今はほぼ使われない化石。(コンセプトは好きだけど。。共通ブロックに問題があって良くない(?))
今はパラメータを集めたモジュールを作ればいい。
nag Fortran 入門: 知識として必要な過去の Fortranが詳しい。
(Fortranは古くから存在するプログラミング言語の中では比較的数式を簡単に表現できるのもあって、アカデミックな、特に地球科学分野などで伝統的に使われていることが多く、時にはFORTRAN77のような読みづらいものが残っていることもある。このページは他にもそのような色んな過去の産物(GO TOとか文番号とか)のことが書いてあって、Fortran95からより古いバージョンを追っていくにあたり非常に助かった。)
※このように、基本色んなプログラム単位の中に内部副プログラムを置くことができるが、内部副の中に内部副とする事だけは不可(内部副プログラムは入れ子構造禁止)。
参考
nag Fortran入門
恐らくインターネット上ではFortran入門として一番見られているサイト。ありがとうありがとう
Fortran 入門: 知識として必要な過去の Fortran
色んな過去の産物のことが書いてあって、Fortran95からより古いバージョンを追っていくにあたって非常に助かった。
数値計算のためのFortran90/95プログラミング入門
有名な書籍(amazon)。最近(2020)第2版が出たみたいなので。。
Fortran演習
とてもわかりやすい。
東京大学理学部地球惑星物理学科の地球惑星物理学演習の授業で作られたみたい。さすが東大
個人的メモ
覚えながら、忘れそうなところを、合間時間を使って書いていく。
コードを読んでてわからなかったところを書く。