fortranでのエラーメモ

gfortranコンパイラで起こったこと。
何はともあれ、エラーが出たらまずはデバッグをしましょう。
gfortranならば

gfortran -Wall -fbounds-check -O -Wuninitialized -ffpe-trap=invalid,zero,overflow -fbacktrace -g main.f90

intel fortran(ifort)ならば

ifort -mkl -check all -warn all -gen_interfaces -fpe0 -ftrapuv -traceback -g main.f90

でコンパイルして実行です。

Program received signal SIGFPE


実行したら、

>./a.out
Program received signal SIGFPE: Floating-point exception - erroneous arithmetic operation.

Backtrace for this error:
#0  0x7F19261E47D7
#1  0x7F19261E4DDE
#2  0x7F1925B35C2F
#3  0x7F1925F2498A
#4  0x7F1925EEB0B2
#5  0x40E9E4 in f_ at main.f90:92
#6  0x40EC7A in func_ at main.f90:50 (discriminator 4)
#7  0x40EE35 in MAIN__ at main.f90:24
Floating point exception

というエラーが出る。

原因

どこかでオーバーフローかアンダーフロー、もしくはゼロ割やルートの中に負の値が入っています。
また、gfortranの場合、gfortranに特有のエラーかもしれません。

例えば、

x=-1.d0
write(6,*)sqrt(x)

となっていたらこのエラーが出ますし、sqrt(x)ではなくてx**1.5d0となっていてもこのエラーは出ます。

オーバーフロー、アンダーフローの場合は、
倍精度型の場合、使える値の範囲はおおよそ\(\pm 10^{-308}\sim\pm 10^{308}\)の範囲までです。
どこかで指数関数を使っていたらその範囲は\(\pm e^{-690}\sim \pm e^{690}\)でなければなりません。
もしも今使っている変数xが10進数でどこまで使えるのか知りたい場合は

write(6,*)huge(x),tiny(x)

とやれば分かります。
倍精度型(double precision)で上の文を書いて実行してみますと(僕の環境では)、

$./a.out
  1.7976931348623157E+308   2.2250738585072014E-308

と出力されます。

gfortran特有の場合、以下のプログラムを試してみてください。
※GNU Fortran (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4 にて検証

program main
  implicit none
  complex*16::f,g
  integer::i

  g=0d0
  do i=0,1
     f=dcmplx(i)
     if(i.eq.0)g=f
  enddo

  write(6,*)g**1d0
 
  stop
end program main

このコードをgfortranのデバッグ用のコマンドで動かした時、

$ gfortran -Wall -fbounds-check -O -Wuninitialized -ffpe-trap=invalid,zero,overflow -fbacktrace -g main.f90
$ ./a.out

Program received signal SIGFPE: Floating-point exception - erroneous arithmetic operation.

Backtrace for this error:
#0  0x7FB51FA9D777
#1  0x7FB51FA9DD7E
#2  0x7FB51F3EFD3F
#3  0x7FB51F7A6415
#4  0x7FB51F7A8053
#5  0x400954 in MAIN__ at main.f90:12
浮動小数点例外
$

というエラーが出るならば、それはgfortran特有の問題かもしれません。実際、ifortでのデバッグではエラーは起こりませんでした。
これは良く分からないエラーで、似たようなエラーが
floating point error gfortran -stack overflowにて報告されています。

これはどうやらデバッグオプションの

-ffpe-trap=invalid,zero,overflow

が悪さしてるようなので、それ消してください。以下のコマンドが適切だと思います。

gfortran -Wall -fbounds-check -O -Wuninitialized -fbacktrace -g main.f90

SIGBUS, SIGSEGV


一つの原因としては、例えばparameterで指定してある変数に値を代入しようとした時にこのエラーが出ることがあります。


スポンサーリンク


fortran77でのエラー


gfortranコンパイラです。

prog2.f:25.22:

      COMMON /q1/aa,an,alpha,beta
Error: COMMON attribute conflicts with DUMMY attribute in 'aa' at (1)

というエラーは、common文を使うために起きる問題です。
僕の場合は、サブルーチンの引数の中に”aa”という変数が入っていたので、これがどうやら原因になるようです。

    subroutine test(aa,...)
    implicit real*8 (A,B,D-H,O-Z)
    COMMON /q1/aa,an,...
    ....
    ....

となっていたものを

    subroutine test(aa0,...)
    implicit real*8 (A,B,D-H,O-Z)
    COMMON /q1/aa,an,...
   
    aa=aa0
    ....
    ....

とするとエラーは無くなりました。

※上の例で使用している暗黙の型宣言とcommon文はまるで推奨されません
古いコードでは当たり前のように上記二つが使われていますが、サブルーチンの引数で渡す、もしくはモジュールによってグローバル変数を定義しましょう。

エラーを起こさないエラー

以下のコードはエラーを起こさず、デバッグしてもエラーが起きていると言ってくれません。
これは大きさ引継ぎ配列と呼ばれるものです。気を付けましょう。

program main
  implicit none
  integer::i
  double precision::a(1:5)
 
  a(1:5)=(/1,2,3,4,5/)

  write(6,'(5f10.5)')a
 
  call test(10,a)
 
  write(6,'(5f10.5)')a

  stop
end program main
 
subroutine test(N,a)
  implicit none
  integer::i,N
  double precision::a(*)
 
  do i=1,N-1
     a(i)=a(i+1)
  enddo

  return
end subroutine test

以下のように実行してもなんとエラーは出さずに終わってしまいます。

$ ifort -mkl -check all -gen_interfaces -fpe0 -ftrapuv -traceback -g test.f90
$ ./a.out
   1.00000   2.00000   3.00000   4.00000   5.00000
   2.00000   3.00000   4.00000   5.00000   0.00000

配列を渡す際は形状引継ぎ配列が推奨されます。
また、引数を省略したい場合、外部サブルーチンではできません。
モジュールを用いて以下のように変えると良いでしょう。

module temp
contains  
  subroutine test(a)
    implicit none
    integer::i,N
    double precision::a(:)

    N=size(a,1)
    write(6,*)N

    do i=1,N-1
       a(i)=a(i+1)
    enddo

    return
  end subroutine test
end module temp

program main
  use temp
  implicit none
  integer::i
  double precision::a(1:5)
 
  a(1:5)=(/1,2,3,4,5/)

  write(6,'(5f10.5)')a
 
  call test(a)
 
  write(6,'(5f10.5)')a

  stop
end program main

実行すると、

$ ifort -mkl -check all -gen_interfaces -fpe0 -ftrapuv -traceback -g test.f90
$ ./a.out
   1.00000   2.00000   3.00000   4.00000   5.00000
           5
   2.00000   3.00000   4.00000   5.00000   5.00000
$

という結果が得られます。

スポンサーリンク

参考:f77 program on gfortran

18.6 大きさ引継ぎ配列-NAG


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です