はじめに
研究で主にJulia, Pythonを使っていたのですが、私がずっと逃げてきたfortranを触る必要が出てきたので、ざっとfortranコードを読めて書くための基本をまとめました。
この記事で分かること
- ざっくりとfortranの書き方, 動かし方が分かる
- 変数の型定義
- 配列
- ループ系の文法
- ファイル入出力
- 標準入出力
- 関数の書き方
- サブルーチンの書き方
- モジュールの書き方
書き方
基本的には以下の例のようなプログラム構成になります。
例として、1~10の総和を取って標準出力にprintするプログラムを載せました。
program main
implicit none ! 暗黙の変数の型に関する規則(変数の先頭がi~nまでだと整数、それ以外では実数になるという規則)を無効にする
! ---------変数定義 ----------------------------------------
integer :: i
real(8) :: nums(10)
real(8) :: total
! ---------実行文 ----------------------------------------
total = 0.d0
do i = 1, 10
nums(i) = i
enddo
total = sum(nums)
write(*, *) 'total = ', total ! 他の言語でいうprint文
! write(ファイル番号, 書式) 出力対象1, 出力対象2,,,
! ファイル番号に* -> 標準出力
! 書式に* -> 並び出力(write文の後に並ぶ変数の型にあった書式で出力される)
end program main
- implicit none
おまじないなので、必ず書く。
意味としては、暗黙の変数の型に関する規則(変数の先頭がi~nまでだと整数、それ以外では実数になるという規則)を無効にするというものになります。
プログラム実行方法
fortranはコンパイルしてから実行するので、gfortran ファイル名.f90
でコンパイルします。
その後、a.outというコンパイルされたファイルが作成されます。
これを実行すればプログラムを実行することができます。
$ gfortran main.f90 #コンパイル
$ ./a.out #プログラム実行
total = 55.000000000000000
変数
型 :: 変数名
- 実数
- 単精度実数(32bit, 6-7桁) real
- 倍精度実数(64bit, 14-16桁) real(8)
- 複素数型
- 単精度 complex
- 倍精度 complex
配列
配列にするときは、型 :: 変数名(要素数) にすればOK.
real(8) :: numbers(100)
real(8) :: matrix(10, 10) !多次元配列
割付け配列
配列のサイズが初期設定として定まらない時には、allocatableという属性をつけると
後からサイズを定義することができる。
real(8), allocatable :: r(:)
integer :: n = 2
allocate (r(n)) ! n=2を割り付ける
! hoge
deallocate (r) ! 割付を解除する
構造体
自分で定義できる型。
複数の型を要素として持つことができる。
type :: name
integer :: nums
real(8) :: total
end type name
do, while, if
! doループ
do i = min, max
! 実行文
enddo
! while ループ
do while (condition)
! 実行文
end do
! if文
if (論理式) then
! 実行文
else if (論理式) then
! 実行文
else
! 実行文
! ex)
stop 'error! something is wrong!' !stop文を使うとエラーを検知できる
endif
ファイル入出力
! 入力
open(10, file='input.dat') ! ファイル番号10で入力ファイルinput.datを開く
read(10, *) x1 ! 1行目の値をx1に代入
read(10, *) x2 ! 2行目の値をx2に代入
close(10) ! ファイルを閉じる
! 出力
open(20, file='output.dat', status='replace') ! ファイル番号20でoutput.datを開く
write(20, *) result1, result2 ! 出力する
close(20)
ファイル番号は任意でOkです.
出力する時のopen(ファイル番号,file=ファイル名, status='?')のstatus:
- old: 事前にファイルが存在している
- new: 事前に存在してはいけない
- replace: 事前に存在していてもしなくてもどっちでもOK
標準入出力
integer :: i
! 入力
read(*,*) i ! 標準入力のinputされた値をiに代入する
! 出力
write(*,*) 'your input i = ', i ! 「your input i = iの値」を標準出力する
副プログラム編
module, subroutine, functionを理解するために以下のプログラムをみてください。
内容は最初のプログラムを同じで1からnまでの総和を取るだけです。
それをmodule, subroutine, functionを使って書いています。
module utils
implicit none
contains
! subroutine
! 配列の総和を計算する
subroutine calc_total(nums, n, total)
implicit none
integer, intent(in) :: n
real(8), intent(in) :: nums(n)
real(8), intent(out) :: total
total = 0.d0
total = sum(nums) ! 総和をとる
end subroutine calc_total
! function
! 1からnまでを要素として格納した配列を返す
function make_nums(n) result(nums)
implicit none
integer, intent(in) :: n
real(8) :: nums(n)
integer :: i
! 配列に1からnを追加する
do i = 1, n
nums(i) = i
end do
end function make_nums
end module utils
program main
use utils ! moduleを呼び出す
implicit none ! 暗黙の変数の型に関する規則(変数の先頭がi~nまでだと整数、それ以 外では実数になるという規則)を無効にする
! ---------変数定義 ----------------------------------------
integer :: i
integer :: n
real(8), allocatable :: nums(:)
real(8) :: total
!real(8) :: factor
integer, parameter :: XNUM = 100
real(8) :: xs(XNUM), ys(XNUM)
! ---------実行文 ----------------------------------------
!標準入力
write(*,*) 'input n : '
read(*,*) n
! 配列numsのサイズをnに割り当てる
allocate(nums(n))
! function
! 1からnを配列numsに格納する
nums = make_nums(n)
! subroutine
! 配列numsの要素の総和を計算してtotalに代入する
call calc_total(nums, n, total)
! 配列numsを解放する
deallocate(nums)
! 標準出力
! write(ファイル番号, 書式) 出力対象1, 出力対象2,,,
! ファイル番号に* -> 標準出力
! 書式に* -> 並び出力(write文の後に並ぶ変数の型にあった書式で出力される)
write(*, *) 'total = ', total
! ファイル出力
open(20, file='output.dat', status='replace')
write(20,*) total
close(20)
end program main
Subroutine
- 書き方
subroutine function_name(arg1, arg2, arg3)
implicit none
型, intent(in) :: arg1
型, intent(in) :: arg2
型, intent(out) :: total
! 実行文
end subroutine calc_total
- 呼び出し方
call subroutine(arg,,,)
- 説明
- サブルーチン内でのみ使う引数(仮引数)にはintent(in)属性をつける
- サブルーチン呼び出し後に戻る変数にはintent(out)属性をつける
- 前回の値を保持させるには、save属性をつける
Function
- 書き方
function name(args,,,) result(output)
implicit none
! 変数宣言
型, intent(in) :: arg
,,,,
型 :: output
!実行文
end function name
- 呼び出し方
function_name(引数,,,)
- 説明
- 関数は単一の変数(output)を返し、引数に演算結果を格納しない
- result句内の変数を返す
- 返す変数は決まっているため、intent(in)属性だけ付ける
module
- 書き方
module name
implicit none
contains
! 中身
! submodule, functionなど
end module name
- 呼び出し方
use module_name
- 補足
- module内でグローバル変数を定義するときは、save属性をつける
参考
数値計算のためのFortran90/95プログラミング入門, 牛島省, 森北出版株式会社