アプリケーション (fortran 90) をデバッグするために、すべての NaN をシグナリング NaN に変更したいと考えています。
デフォルト設定では、私のプログラムは信号なしで動作し、ファイルに NaN データを出力するだけです。NaN が生成されるポイントを見つけたい。シグナリング NaN を使用してプログラムを再コンパイルできればSIGFPE
、最初の間違った浮動小数点演算が存在する最初のポイントでシグナルを取得できます。
お探しのフラグは-ffpe-trap=invalid
; ,zero,overflow
私は通常、関連する浮動小数点例外をチェックするために 追加します。
program nantest
real :: a, b, c
a = 1.
b = 2.
c = a/b
print *, c,a,b
a = 0.
b = 0.
c = a/b
print *, c,a,b
a = 2.
b = 1.
c = a/b
print *,c,a,b
end program nantest
次に、それをコンパイルしてデバッガーで実行すると、次のようになります。
$ gfortran -o nantest nantest.f90 -ffpe-trap=invalid,zero,overflow -g -static
$ gdb nantest
[...]
(gdb) run
Starting program: /scratch/ljdursi/Testing/fortran/nantest
0.50000000 1.0000000 2.0000000
Program received signal SIGFPE, Arithmetic exception.
0x0000000000400384 in nantest () at nantest.f90:13
13 c = a/b
Current language: auto; currently fortran
intel fortran コンパイラ (ifort) では、オプション-fpe0
を使用すると同じことが行われます。
C/C++ コードでは少しトリッキーです。実際に への呼び出しを挿入する必要がfeenableexcept()
あります。これにより、浮動小数点例外が有効になり、 で定義されfenv.h
ます。
#include <stdio.h>
#include <fenv.h>
int main(int argc, char **argv) {
float a, b, c;
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
a = 1.;
b = 2.;
c = a/b;
printf("%f %f %f\n", a, b, c);
a = 0.;
b = 0.;
c = a/b;
printf("%f %f %f\n", a, b, c);
a = 2.;
b = 1.;
c = a/b;
printf("%f %f %f\n", a, b, c);
return 0;
}
しかし、効果は同じです:
$ gcc -o nantest nantest.c -lm -g
$ gdb ./nantest
[...]
(gdb) run
Starting program: /scratch/s/scinet/ljdursi/Testing/exception/nantest
1.000000 2.000000 0.500000
Program received signal SIGFPE, Arithmetic exception.
0x00000000004005d0 in main (argc=1, argv=0x7fffffffe4b8) at nantest.c:17
17 c = a/b;
いずれにせよ、エラーが発生している場所をより適切に処理できます。