Fortran

2023年3月 5日 (日)

[Fortran]文字列の前後の空白を取り除く

trim関数とadjustl関数を組み合わせて使う。trim関数は、文字列の末尾の空白を取り除く関数。adjustl関数は、文字列の先頭の空白を取り除く関数。

以下のプログラムを実行してみる。

program testtrim
implicit none
character(len=10) :: str
str=' ABC '
write(*,'(a)') '>'//str//'<'
write(*,'(a)') '>'//trim(str)//'<'
write(*,'(a)') '>'//trim(adjustl(str))//'<'
end program testtrim

出力

>  ABC     <
> ABC<
>ABC<

2021年1月31日 (日)

[Fortran]write文で出力時に改行させない

$かadvanceオプションにnoを指定する。

write(*,'(a)') 'AB'
write(*,'(a)') 'CD'
write(*,'(a,$)') '12'
write(*,'(a)') '34'
write(*,'(a)',advance='no') '56'
write(*,'(a)') '78'
end

実行結果

>a.exe
AB
CD
1234
5678

GNU Fortran 8.2.0で動作確認をしている。

2021年1月 9日 (土)

[Fortran]サブルーチンの引数にサブルーチンを指定する

external文を使用すると、サブルーチンの引数に変数や配列以外に、サブルーチンを指定することもできる。以下はWindowsのgfortranで実行した例。説明を簡単にするために、簡略化して記述しているので注意。

メインルーチンで、サブルーチンsub1を呼び出しているが、そのsub1を呼び出し時に、引数にsub2を指定し、sub1ではその指定されたsub2をさらに呼び出している。メインルーチンで、呼び出される側で呼び出すサブルーチンをexternal文で指定しておく必要がある。

external sub2
call sub1(sub2, 10)
end

subroutine sub1(sname, n)
integer n
write(*, '(a,1x,i3)') 'A', n + 1
call sname(n + 2)
write(*, '(a,1x,i3)') 'C', n + 3
end subroutine

subroutine sub2(n)
integer n
write(*, '(a,1x,i3)') 'B', n
end subroutine

実行結果

>a.exe
A 11
B 12
C 13

2020年8月16日 (日)

[GNU Fortran]ファイル(ディレクトリ)の存在を確認

access関数を使う。第一引数に存在の有無を確認したいファイル名かディレクトリ名。第二引数に「r」を指定する。第一引数に指定をしたファイル(ディレクトリ)が存在した場合は0、存在しない場合は0以外を返す。

program test
implicit none
integer n
n = access('C:\Windows', 'r')
print *, n
n = access('C:\Win', 'r')
print *, n
n = access('C:\Windows\write.exe', 'r')
print *, n
n = access('C:\Windows\wri.exe', 'r')
print *, n
n = access('C:\Windows\', 'r')
print *, n
n = access('C:\Windows\write.exe\', 'r')
print *, n
end program test

出力結果(環境により異なる)。

>test.exe
0
2
0
2
0
22

ファイルかディレクトリの判別は、上記の最後2つの例のとおりに、第一引数のパスの最後にパス区切り文字(ウィンドウズの場合は¥)を付ける。パス区切り文字を最後に付けると、それはディレクトリと判断して存在の有無が確認される。

access関数はGNU拡張機能(GNU extension)であることに注意。

2020年7月20日 (月)

[gfortran]エラーメッセージ「Program received signal SIGSEGV: Segmentation fault - invalid memory reference.」

gfortranの古いバージョンにはバグがあり、ブログラムに間違いがなくても、このエラーメッセージが表示されることがある。

>a.exe
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 ○○
(以下、表示省略)

ソースコードに誤りがなくてもこのメッセージが表示される場合は、gfortranのバージョンを上げてみる。例えば、以下のバージョンだと、このエラーメッセージが表示されることが多いようだ。

>gfortran --version
GNU Fortran (MinGW.org GCC-6.3.0-1) 6.3.0

2020年7月時点の最新バージョンは以下のとおり。

>gfortran --version
GNU Fortran (MinGW.org GCC Build-20200227-1) 9.2.0

このバージョンでは、上記のエラーメッセージが表示されることは少ないはず。

2019年12月17日 (火)

[gfortran]配列へのインデックスの指定のチェックと-fbounds-checkオプション

Fortranの配列の要素番号(インデックス)は、通常は1~であり、値を取り出すために指定をするインデックスは自然数で指定することになる。しかし、デフォルトでは、このインデックスの指定のチェックは甘い。例えば以下のソースコードを実行してみる。

implicit none
integer a, b
dimension a(3)
a(1) = 1
b = 0
a(2) = a(b)
b = -1
a(3) = a(b)
write(*,'(3(I3,1X))') a(1),a(2),a(3)
end

実行すると、以下のようになる。

>gfortran.exe -o array.exe array.f
>array.exe
1 0 0

配列aのインデックスに0や-1を指定しているのに、値が取り出せてしまっている。これを防ぐためには、コンパイル時に-fbounds-checkオプションを使用する。

>gfortran.exe -fbounds-check -o array.exe array.f
>array.exe
At line 6 of file array.f
Fortran runtime error: Index '0' of dimension 1 of array 'a' below lower bound of 1
Error termination. Backtrace:
Could not print backtrace: libbacktrace could not find executable to open
(以下省略)

配列のインデックスに0を指定していることが、実行時にチェックされており、この例ではプログラムが緊急停止していることがわかる。なお、上記のことは以下のコンパイラーで実行している。環境はWindows。

>gfortran --version
GNU Fortran (MinGW.org GCC-8.2.0-3) 8.2.0

2019年2月 6日 (水)

[Fortran]小数を整数に変換するint関数の挙動

int関数は小数を整数に変換する。gfortranにおけるその機能の挙動確認。
以下のプログラムを動作してみる。

program test
    write(*,*) int(2.4d0)
    write(*,*) int(2.5d0)
    write(*,*) int(2.6d0)
    write(*,*) int(-2.4d0)
    write(*,*) int(-2.5d0)
    write(*,*) int(-2.6d0)
end program

(出力結果)

2
2
2
-2
-2
-2

上記のとおり、単純に小数点以下を切り捨てているだけである。0に近い値へ寄せるようなことなどはしていない。

2015年7月 5日 (日)

[gfortran]Windows 8.1でFortran

MinGWを使えば、Windows 8.1で無料で使えるFortranコンパイラーが使える。

以下のページを開く。
http://www.mingw.org/wiki/msys

左側のメニュー、「Navigation」→「Downloads」をクリック。sourceforgeのページに飛ぶ。

いろいろ表示されているが、「Looking for the latest version?」とある隣の「Download mingw-get-setup.exe (86.5 kB)」をクリックして、mingw-get-setup.exeをダウンロードする。なお、これは各種プログラムをダウンロードするだけのプログラム(インストーラー)に過ぎない。

ダウンロードしたmingw-get-setup.exeを起動する。C:\MinGWにインストールしようとするので、インストーラーの指示に従ってインストールする。

デスクトップにアイコン「MinGW Installer」が作成されたはず。これをダブルクリックして、MinGW Installerを起動する。

左側のメニュー「Basic Setup」をクリックすると、右側上部にいろいろ表示されるが、「mingw32-base」、「mingw32-gcc-fortran」、「mingw32-gcc-g++」の3つのパッケージがあるはず。これを選択する(右クリックで現れたメニューから「Mark for Installation」をクリック)。

上部のメニュー「Installation」→「Apply Changes」を選択し、現れたダイアログのボタン「Apply」をクリックすると、インストールが始まる。

パスを通す。環境変数PathにC:\MinGW\binを追加する。

2015年1月15日 (木)

[Fortran]組み込み関数の個別名と総称名について(dsinとsin、dabsとabsなど)

Fortranの組み込み関数(Fortranに標準で搭載されている関数)には個別名と総称名を持つものがある。具体的にはdsinとsin、dabsとabsなどである。

これらはその組み込み関数の引数と戻り値の肩に関するものである。上の例では、dsinとdabsはその関数の引数には倍精度浮動小数点型の変数しか扱えない。これらdsinやdabsといった名前を個別名と呼ぶ。

一方、sinやabsは総称名と呼ばれ、これらは関数の引数に与えられた型を自動で判定して計算し、その関数のも度値も引数で与えた型で返す。

以下は実行例。

program sosho
    implicit none
    real r
    double precision d
    r = 3.14
    d = 3.14d0
    print '(f20.18)', r        ! 単精度定数
    print '(f20.18)', d        ! 倍精度定数
    print '(f20.18)', sin(r)   ! 単精度で計算(総称名)
    print '(f20.18)', dsin(d)  ! 倍精度で計算
    print '(f20.18)', sin(d)   ! 倍精度で計算(総称名)
end program sosho

出力は以下のとおり。

3.140000104904174805
3.140000000000000124
0.001592547981999815
0.001592652916486828
0.001592652916486828

2015年1月 9日 (金)

[Fortran]単精度浮動小数点数と倍精度浮動小数点数

Fortranでは浮動小数点数(※)を扱うとき、変数へ定数を代入するときには単精度が倍精度を明示しなければならない。

例えば、倍精度浮動小数点型の変数へ代入する際、数値定数を「3.14」としただけでは単精度浮動小数点数とみなされてしまう。この場合、有効桁数は6桁程度しかない。指数部に「E」あるいは「e」を使用した場合も同じ。

高精度な数値計算を行いたくて倍精度浮動小数点数で計算を行う場合は、数値定数の指数部に「D」あるいは「d」を用いた表記を使用すること。

以下の例では、倍精度浮動小数点型の変数に代入する際、数値定数の表記による数値の取扱いの差を示したもの。指数部を「d」を使用して表記しなければ倍精度で扱われていないことがわかる。

program doublecheck
    implicit none
    double precision d1, d2, d3
    d1 = 3.14
    d2 = 3.14e0
    d3 = 3.14d0
    print '(f20.18)', d1
    print '(f20.18)', d2
    print '(f20.18)', d3
end program

出力

3.140000104904174805
3.140000104904174805
3.140000000000000124

※Fortranに関する書籍では「実数」と表記するものが多いが、これは簡便な表記であり、プログラミング言語の分野では実数を「浮動小数点数」と呼ぶことが多い。