4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Fortran90の基本文法まとめ

Last updated at Posted at 2022-07-03

はじめに

大気科学や海洋学や惑星科学などの地球物理学分野では、現代でもFortranが主流です。自分も研究で使用するため、いつでも確認できるように自分用のまとめ記事を書きました。とりあえず暗黙の型宣言を無効にしておきましょう。

program main
    implicit none
end program main

目次

  1. 基礎文法
  2. 型宣言
  3. 制御構文
  4. 入出力
  5. サブプログラム
  6. コンパイルと実行

注:これまで学んだ知識はFORTRAN77とFortran90/95の両方が混ざっているので、いくつかFortran90/95に当てはまらないものがあるかもしれません。

1. 基礎文法

  • 添字は1スタート
  • コメントアウトは!(77で使用されていたCも可)
  • 文字列は"Hello"'Hello'どちらでもよい
  • 1行に書ける文字数は132文字
  • コード中の改行は&
implicit noneについて

おまじない
iからnまでの英字を型名に指定すると、自動的に整数として扱われます。これは暗黙の型宣言と呼ばれます。思わぬエラーの原因にもなるので、implicit noneで無効にし、自分で型宣言を行います。

例:ローレンツ・アトラクタの簡易式

lorenz.f90
!ここはコメント
!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は最初に変数・定数・配列等を全て指定する必要があります。

  • 大文字と小文字は区別しない(ansANSは併用できない)
  • 先頭の文字に数字は使用できない
  • -.は使用できない

変数・定数

デフォルトでrealintegerは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. 入出力

ファイルの読み書きの大まかな流れです。

  1. openでファイルを開く
  2. readでファイルを読む
  3. 読み取ったデータを操作する
  4. 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(引数)で呼び出すことが出来ます。

sort.f90
!バブルソート
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つ返します。

gcd_lcm.f90
!最大公約数と最小公倍数を求める
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とはまだまだ長い付き合いになりそうなので、もっと勉強してもっと仲良くなれればいいなと思っています。

参考サイト

Fortran演習 (地球惑星物理学演習), 東京大学, 2022

Fortran入門, nag

Fortranでバイナリを読み書きするときのあれこれ

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?