浮動小数点例外の処理

浮動小数点例外が無効 (SETCONTROLFPQQ (x87 演算のみ) により 1 に設定) の場合は、例外が発生しても割り込み信号は生成されません。浮動小数点プロセスは適切な特殊値 (NaN や符号付き無限大など) または許容値 (正規化されていないオペランドなど) を返し、プログラムは実行を続けます。浮動小数点例外が有効 (0 に設定) の場合は、例外が発生したときには割り込み信号 (ソフトウェア割り込み) が生成されます。

次の表は、浮動小数点例外の信号のリストです。

パラメーター名

16 進値

説明

FPE$INVALID

#81

無効な結果

FPE$DENORMAL

#82

正規化されていないオペランド

FPE$ZERODIVIDE

#83

ゼロ除算

FPE$OVERFLOW

#84

オーバーフロー

FPE$UNDERFLOW

#85

アンダーフロー

FPE$INEXACT

#86

不正確 (精度)

浮動小数点例外割り込みが発生し、プログラマーにより例外処理ルーチンが用意されていなかった場合、ランタイムシステムは、/fpe コンパイラー・オプションにより選択された動作に従って割り込みに対応します。割り込みは例外が有効になっている (0 に設定) ときにのみ発生することに注意してください。

デフォルトのシステム例外処理を行いたくない場合、独自の割り込み処理ルーチンを作成する必要があります。

割り込み処理ルーチンは cDEC$ ATTRIBUTES option C を使用しなければならないことに注意してください。

独自のルーチンを作成することの短所は、例外処理ルーチンが、例外を発生したプロセスに返ることができないという点です。これは、例外処理ルーチンが呼び出された時点で浮動小数点プロセッサーがエラー状態にあり、ルーチンが返ると、プロセッサーはシステムを終了させたのと同じ状態にあるためです。このため、例外処理ルーチンは別のプログラムユニットに分岐するか、(プログラム状態を保存して適切なメッセージを出力した後に) 終了するかのいずれかを行うしかありません。例外処理ルーチンを呼び出したプログラムユニット中の別の文に返ることはできません。これは、グローバルな GOTO は存在せず、浮動小数点プロセッサー中のステータスワードをリセットすることはできないためです。

例外が発生したらそのことを把握し、実行を続ける必要がある場合、割り込みを引き起こさないように例外を無効にした上で、GETSTATUSFPQQ (IA-32 アーキテクチャーのみ) を使用して定期的に浮動小数点ステータスワードを調査し、例外が発生したかどうかを調べなければなりません。ステータス・ワード・フラグをクリアするには、CLEARSTATUSFPQQ (IA-32 アーキテクチャーのみ) ルーチンを呼び出します。

定期的に浮動小数点ステータスワードを調査すると、プログラムの処理にオーバーヘッドが生じます。一般に、例外が発生したらプログラムを終了させるほうが良いでしょう。次に例外処理ルーチンの例を示します。SIGTEST.F90 ファイルの先頭の注釈に、この例のコンパイル方法が記されています。

 ! SIGTEST.F90

 ! Establish the name of the exception handler as the

 ! function to be invoked if an exception happens.

 ! The exception handler hand_fpe is attached below.

   USE IFPORT

      INTERFACE

        FUNCTION hand_fpe (sigid, except)

           !DEC$ ATTRIBUTES C :: hand_fpe

           INTEGER(4) hand_fpe

           INTEGER(2) sigid, except

        END FUNCTION

      END INTERFACE

 INTEGER(4) iret

 REAL(4) r1, r2

 r1 = 0.0

 iret = SIGNALQQ(SIG$FPE, hand_fpe)

 WRITE(*,*) 'Set exception handler. Return = ', iret

 ! Cause divide-by-zero exception

 r1 = 0.0

 r2 = 3/r1

 END

 ! Exception handler routine hand_fpe

   FUNCTION hand_fpe (signum, excnum)

     !DEC$ ATTRIBUTES C :: hand_fpe

     USE IFPORT

     INTEGER(2) signum, excnum

     WRITE(*,*) 'In signal handler for SIG$FPE'

     WRITE(*,*) 'signum = ', signum

     WRITE(*,*) 'exception = ', excnum

     SELECT CASE(excnum)

       CASE( FPE$INVALID )

         STOP ' Floating point exception: Invalid number'

       CASE( FPE$DENORMAL )

         STOP ' Floating point exception: Denormalized number'

       CASE( FPE$ZERODIVIDE )

         STOP ' Floating point exception: Zero divide'

       CASE( FPE$OVERFLOW )

         STOP ' Floating point exception: Overflow'

       CASE( FPE$UNDERFLOW )

         STOP ' Floating point exception: Underflow'

       CASE( FPE$INEXACT )

         STOP ' Floating point exception: Inexact precision'

       CASE DEFAULT

         STOP ' Floating point exception: Non-IEEE type'

     END SELECT

     hand_fpe = 1

   END