浮動小数点演算例外の検出とトラッピング

始めに述べたとおり、浮動小数点算術演算に関する IEEE 標準は、 回避または回復に特別な注意が必要な多数の例外 (エラー) 条件を規定しています。 以下の項は、このような例外条件が存在する中でプログラムを安全に作動させ、 その一方で、犠牲にするパフォーマンスを最小にとどめるのに役立つ内容になっています。

浮動小数点ハードウェアは、常に多数の浮動小数点演算の例外条件 (これは、 IEEE 標準で厳格に規定されています) を検出します。 たとえば、オーバーフロー、アンダーフロー、ゼロ除算、無効、および不正確さなどです。

デフォルト時には、とられるアクションは状況フラグの設定だけです。 プログラムは問題なく処理を続行します (それ以降の結果は予測どおりでない場合もあります)。 例外がいつ発生するかを知りたい場合は、シグナルを生成するように、 これらの例外条件の内の 1 つまたは複数を調整することができます。

シグナルによってハンドラー・ルーチンへの分岐が生じます。 シグナルが生じたときに、ハンドラーはシグナルのタイプとプログラムの状態についての情報を受け取ります。 ハンドラーはメモリー・ダンプの生成、例外が発生した場所のリストの表示、計算結果の変更、またはその他の 指定された処理の実行を行うことができます。

XL Fortran コンパイラーは、浮動小数点例外条件の処理に オペレーティング・システム機能を使用します。 これらの機能は、SIGFPE シグナルを生成することにより、浮動小数点例外の存在を示します。

浮動小数点演算例外をトラッピングするためのコンパイラー機能

XL Fortran の例外トラッピングをオンにするには、-qflttrap オプション、 および enable を含むサブオプションの組み合わせを指定して、 プログラムをコンパイルします。 このオプションはトラップ操作を使用して浮動小数点例外を検出し、 例外発生時に SIGFPE シグナルを 生成します。

-qflttrap は、例外条件の名前に対応するサブオプションも持っています。 たとえば、オーバーフローおよびアンダーフロー例外の処理のみに関心がある場合は、 次のように指定することができます。

  xlf95 -qflttrap=overflow:underflow:enable compute_pi.f
enable が必要なのは、メインプログラムをコンパイルするときだけですが、ただし、これは非常に 重要であり、他のファイルに対して指定しても何の問題も発生させないので、-qflttrap を使用する場合は、 常にこれを入れるようにしてください。

このアプローチの利点は、パフォーマンスの影響が比較的少なくなることです。 パフォーマンスの影響をさらに少なくするために、-qflttrap オプションの imprecise サブオプションを入れることができます。 これによって、プログラムがサブプログラムの始まりまたは終わりに達するまで、トラッピングが遅れます。

この方法の欠点は次のとおりです。

注:

  1. ご使用中のプログラムが、特定の演算に対して発生する浮動小数点演算の例外に 依存している場合は、nofold が入っている -qfloat サブオプションも指定して ください。 そのようにしないと、コンパイラーは例外を発生させる計算を一定の NaN または無限大の値と置き換えるか、 または、単精度演算におけるオーバーフローを除去します。

  2. -qflttrap オプションのサブオプションによって、コードの変更を必要とした初期の手法は、 fpsets および fpgets プロシージャーへの呼び出しに置き換わります。 適切な -qflttrap 設定を使用すれば、もうこれらの例外処理ハンドルを呼び出す必要はなくなります。

    重要: 浮動小数点演算の例外チェックを使用可能にする fpsets 呼び出しが コードに入っているときに、-qflttrap オプションを使用しないでプログラム全体をコンパイルすると、 表 14 に説明してあるように、例外発生時にプログラムは予期しない結果を発生させます。

例外ハンドラーのインストール

XL Fortran または Linux の例外検出機能を使用するプログラムは、 例外条件を検出すると、シグナルを生成します。 これによって、プログラムによってどのハンドラーが指定されていても、その指定されているハンドラーへの 分岐が発生します。

デフォルト時には、プログラムはコア・ファイル (これをデバッガーとともに使用して問題を突き止めることができます) を作成してから停止します。 SIGTRAP または SIGFPE シグナル・ハンドラーを インストールしたい場合は、-qsigtrap オプションを使用してください。 これによって、トレースバックを作成する XL Fortran ハンドラーまたは自分が作成したハンドラーを使用できるようになります。

xlf95 -qflttrap=ov:und:en pi.f                             # Dump core on an exception
xlf95 -qflttrap=ov:und:en -qsigtrap pi.f                   # Uses the xl__trce handler
xlf95 -qflttrap=ov:und:en -qsigtrap=return_22_over_7 pi.f  # Uses any other handler

SIGNAL サブルーチン ( /opt/ibmcmp/xlf/9.1/include/fexcp.h に定義されています) を呼び出すことによって、XL Fortran が提供するものでも、自分が作成したものでも、 代替の例外ハンドラーをインストールすることができます。

  INCLUDE 'fexcp.h'
  CALL SIGNAL(SIGTRAP,handler_name)
  CALL SIGNAL(SIGFPE,handler_name)
 

XL Fortran には次のような例外ハンドラーと関連ルーチンがあります。

xl__ieee
トレースバックおよびシグナルの説明を作成し、 失敗した計算にデフォルト IEEE 結果を提供することによって実行を継続します。 このハンドラーを使用すると、 プログラムは例外検出がオンになっていない場合と同じ結果を作成します。

xl__trce
トレースバックを作成し、プログラムを停止します。

xl__trcedump
トレースバックとコア・ファイルを作成し、プログラムを停止します。

xl__sigdump
呼び出された地点から出発するトレースバックを提供し、 シグナルに関する情報を提供します。 これは、ユーザー作成のシグナル・ハンドラー内からしか 呼び出すことができません。 このハンドラーはプログラムを停止しません。 正常に継続するために、シグナル・ハンドラーはこのサブプログラムを呼び出した後に終結処理を行う必要があります。

xl__trbk
呼び出された地点から出発するトレースバックを提供します。 このハンドラーは、-qsigtrap オプションで指定するのではなく、 コードからサブルーチンとして呼び出します。 パラメーターは必要ではありません。 このハンドラーはプログラムを停止しません。

これらのハンドラー名のすべてに、 プログラム内で宣言した名前と重複しないよう 2 つの下線が付いています。 また、これらのルーチンはすべて SIGTRAP シグナルと SIGFPE シグナルの両方に対して機能します。

-g コンパイラー・オプションを使用すると、トレースバック・リスト内の行番号を知ることができます。 ファイル /opt/ibmcmp/xlf/9.1/include/fsignal.h では、 signal.h システム・ヘッダー 内の sigcontext 構造体に似ている Fortran 派生型が定義されています。 この派生型にアクセスする Fortran シグナル・ハンドラーを作成できます。

関連情報:
例外処理のためのサンプル・プログラムには、これらのシグナル・ハンドラーの 使用法およびご自分で作成する方法を示すサンプル・プログラムがリストされています。 詳細については、「XL Fortran ランゲージ・リファレンス」の『組み込みプロシージャー』 の節にある『SIGNAL』を参照してください。

浮動小数点状況および制御レジスターの制御

-qflttrap サブオプションまたは -qsigtrap オプションができる前は、 浮動小数点例外に対する処理を行うために、ソース・ファイルを変更して例外トラッピングをオンにしたり、 シグナル・ハンドラーをインストールしなければならない場合がほとんどでした。 現在でもそのようにできますが、新しいアプリケーションの場合は、 このオプションの使用をお勧めします。

実行時に例外処理を停止するには、 -qflttrap オプションの enable サブオプションを指定しないでコンパイルします。

   xlf95 -qflttrap compute_pi.f     # Check all exceptions, but do not trap.
   xlf95 -qflttrap=ov compute_pi.f  # Check one type, but do not trap.

次に、プログラム内で fpstats 配列 (インクルード・ファイル /opt/ibmcmp/xlf/9.1/include/fpdc.h に定義されている) を操作して、fpsets サブルーチンを呼び出し、トラップを発生させる例外を指定します。

丸めモードの選択にある fpsetsfpgets を使用したサンプル・プログラムを 参照してください。

別の方法として、xlf_fp_util モジュールの中の set_fpscr_flags() サブルーチンを 使用する方法があります。 このサブルーチンを使用すると、MASK 引き数で指定する浮動小数点状況と制御レジスター・フラグを 設定することができます。 MASK で指定していないフラグには影響がありません。 MASK は、型 INTEGER(FPSCR_KIND) でなければなりません。 たとえば、次のようになります。

 USE, INTRINSIC :: xlf_fp_util
 INTEGER(FPSCR_KIND) SAVED_FPSCR
 INTEGER(FP_MODE_KIND) FP_MODE
 
 SAVED_FPSCR = get_fpscr()           ! Saves the current value of
                                     ! the fpscr register.
 
 CALL set_fpscr_flags(TRP_DIV_BY_ZERO) ! Enables trapping of
 ! ...                                 ! divide-by-zero.
 SAVED_FPSCR=set_fpscr(SAVED_FPSCR)    ! Restores fpscr register.

別の方法として、ieee_exceptions モジュールの中の ieee_set_halting_mode サブルーチンを使用する方法があります。 この移植可能な ELEMENTAL サブルーチンを使用して、任意の FPSCR 例外フラグの停止 (トラッピング) 状況を 設定することができます。 たとえば、次のようになります。

USE, INTRINSIC :: ieee_exceptions
 TYPE(IEEE_STATUS_TYPE) SAVED_FPSCR
 CALL ieee_get_status(SAVED_FPSCR)   ! Saves the current value of the
                                     ! fpscr register
 
 CALL ieee_set_halting_mode(IEEE_DIVIDE_BY_ZERO, .TRUE.)  ! Enabled trapping
 ! ...                                                    ! of divide-by-zero.
 
 CALL IEEE_SET_STATUS(SAVED_FPSCR)  ! Restore fpscr register

xlf_fp_util プロシージャー

xlf_fp_util プロシージャーを使用すると、 浮動小数点状況とプロセッサーの制御レジスター (fpscr) を直接照会したり制御することができます。 これらのプロシージャーは、浮動小数点状況と制御レジスターを直接操作する インライン・マシン・インストラクションにマップされるため、fpsets および fpgets サブルーチンより効率的です。

組み込みモジュール xlf_fp_util には、これらのプロシージャーの インターフェースとデータ型定義、およびプロシージャーで必要な名前付き定数の定義が入っています。 このモジュールでは、これらのプロシージャーのタイプを、リンク時ではなくコンパイル時に検査することができます。 xlf_fp_util モジュールには、 以下のファイルが提供されています。


ファイル名 ファイル・タイプ ロケーション
xlf_fp_util.mod モジュール・シンボル・ファイル (32 ビット) /opt/ibmcmp/xlf/9.1/include
モジュール・シンボル・ファイル (64 ビット) /opt/ibmcmp/xlf/9.1/include64

プロシージャーを使用するには、ソース・ファイルに USE XLF_FP_UTIL ステートメントを追加する 必要があります。 詳細については、「XL Fortran ランゲージ・リファレンス」の『USE』を参照してください。

-U オプションを指定してコンパイルする場合は、 これらのプロシージャーの名前をすべて小文字でコーディングする必要があります。

xlf_fp_util プロシージャーのリストについては、 「XL Fortran ランゲージ・リファレンス」の『サービス・ プロシージャーおよびユーティリティー・プロシージャー』の節を 参照してください。

fpgets および fpsets サブルーチン

サブルーチン fpsets および fpgets は、浮動小数点状況レジスター と制御レジスターの操作または照会を行う方法を提供します。 オペレーティング・システム・ルーチンを直接呼び出す代わりに、fpstat (論理値の配列) 内で情報を やりとりします。 次の表は、例外を処理する配列エレメントで、最もよく使用されるものを示しています。

表 16. fpsets および fpgets とともに使用するための例外ビット

可能にセットする
配列エレメント
例外が発生したか
どうかを検査する
配列エレメント
.TRUE. の場合に示される例外
n/a fpstat(fpfx) 浮動小数点演算例外の要約
n/a fpstat(fpfex) 浮動小数点使用可能例外の要約
fpstat(fpve) fpstat(fpvx) 浮動小数点無効演算例外の要約
fpstat(fpoe) fpstat(fpox) 浮動小数点オーバーフロー例外
fpstat(fpue) fpstat(fpux) 浮動小数点アンダーフロー例外
fpstat(fpze) fpstat(fpzx) Zero-divide (ゼロ除算) 例外
fpstat(fpxe) fpstat(fpxx) Inexact (不正確) 例外
fpstat(fpve) fpstat(fpvxsnan) 浮動小数点無効演算例外 (シグナル NaN)
fpstat(fpve) fpstat(fpvxisi) 浮動小数点無効演算例外 (INF-INF)
fpstat(fpve) fpstat(fpvxidi) 浮動小数点無効演算例外 (INF/INF)
fpstat(fpve) fpstat(fpvxzdz) 浮動小数点無効演算例外 (0/0)
fpstat(fpve) fpstat(fpvximz) 浮動小数点無効演算例外 (INF*0)
fpstat(fpve) fpstat(fpvxvc) 浮動小数点無効演算例外 (無効な比較)
n/a fpstat(fpvxsoft) 浮動小数点無効演算例外 (ソフトウェア要求)、PowerPC のみ
n/a fpstat(fpvxsqrt) 浮動小数点無効演算例外 (無効な平方根)、PowerPC のみ
n/a fpstat(fpvxcvi) 浮動小数点無効演算例外 (無効な整数変換)、PowerPC のみ

プログラム内の特定のポイントで特定の例外を明示的にチェックするには、fpgets を使用してから、 fpstat 内のエレメントが変更されたかどうかをテストします。 いったん例外が発生すると、対応する例外ビット (上記の表の 2 番目の欄) は、明示的にリセットされるまで 設定されています。 ただし、fpstat(fpfx)fpstat(fpvx)fpstat(fpfex) は除きます。 これらは、特定のビットがリセットされる場合のみリセットされます。

fpgets および fpsets サブルーチンを使用する利点 (-qflttrap オプションで すべてを制御するのとは対照的) には、例外チェックの細分化の制御も含まれます。 たとえば、プログラムの終了時に、プログラムの任意の場所で例外が発生したかどうかだけをテストしたい 場合などです。

この方法の欠点は次のとおりです。

たとえば、プログラムのある一定のセクションでのみ、 浮動小数点オーバーフロー例外をトラップするには、 fpstat(fpoe).TRUE. に設定して、fpsets を呼び出します。 例外が発生した後、対応する例外ビット fpstat(fpox) は、 次のようにプログラムが実行されるまで .TRUE. に設定されます。

      call fpgets(fpstat)
      fpstat(fpox) = .FALSE.
      call fpsets(fpstat)   ! resetting fpstat(fpox) to .FALSE.

例外処理のためのサンプル・プログラム

/opt/ibmcmp/xlf/9.1/samples/floating_point には、例外処理の異なる面を説明するために多くのサンプル・プログラムが入っています。

flttrap_handler.c  および  flttrap_test.f
C 言語で作成された例外ハンドラーのサンプルと、 それを使用する Fortran プログラムです。

xl__ieee.F   および   xl__ieee.c
例外を発生させる演算の特定の値を置き換える方法を示す、 Fortran と C 言語で書かれた例外ハンドラーです。 このようなサポート・コードが使用される場合でも、 XL Fortran 例外処理のインプリメンテーションは、 IEEE 浮動小数点標準が提唱している例外処理環境を完全にはサポートしていません。

check_fpscr.f  および  postmortem.f
fpsets プロシージャーと fpgets プロシージャーおよび fpstats 配列を使って作業する方法を示します。

fhandler.F
サンプルの Fortran シグナル・ハンドラーを示し、 xl__sigdump プロシージャーをデモします。

xl__trbk_test.f
xl__trbk プロシージャーを使用してプログラムを停止せずにトレースバック・リストを生成する方法を示します。

サンプル・プログラムは、例示することだけを目的にしています。

特定の変数に対して例外を発生させるには

変数に「使用しない」というマークを付けるために、 変数内にシグナル NaN と呼ばれる特殊値をエンコードします。 それによって、計算でその変数が使用されるたびに、 効力のない例外条件を発生させることができます。

この手法を使用する場合は、シグナル NaN が使用されるすべてのケースを プログラムが正しく検出するように、-qfloat オプションの nans サブオプションを使用し、 対応する SIGFPE シグナルを 生成するための方法 (前述) のいずれかを使用してください。

注:

  1. 計算結果としてシグナル NaN が生成されることはなく、シグナル NaN は 定数としてプログラムまたは入力データに明示的に取り入れられなければならないため、 その中でシグナル NaN 値を故意に使用しない限り、この手法を使用する必要はありません。

浮動小数点演算例外のトラッピングによるパフォーマンスへの影響の最小化

浮動小数点演算例外条件を処理したいが、プログラムがあまり遅くならないよう にしたい場合、以下にパフォーマンスへの影響を最小化するのに役立つ手法をいくつか示します。

IBM Copyright 2003