始めに述べたとおり、浮動小数点算術演算に関する IEEE 標準は、 回避または回復に特別な注意が必要な多数の例外 (エラー) 条件を規定しています。 以下の項は、このような例外条件が存在する中でプログラムを安全に作動させ、 その一方で、犠牲にするパフォーマンスを最小にとどめるのに役立つ内容になっています。
浮動小数点ハードウェアは、常に多数の浮動小数点演算の例外条件 (これは、 IEEE 標準で厳格に規定されています) を検出します。 たとえば、オーバーフロー、アンダーフロー、ゼロ除算、無効、および不正確さなどです。
デフォルト時には、とられるアクションは状況フラグの設定だけです。 プログラムは問題なく処理を続行します (それ以降の結果は予測どおりでない場合もあります)。 例外がいつ発生するかを知りたい場合は、シグナルを生成するように、 これらの例外条件の内の 1 つまたは複数を調整することができます。
シグナルによってハンドラー・ルーチンへの分岐が生じます。 シグナルが生じたときに、ハンドラーはシグナルのタイプとプログラムの状態についての情報を受け取ります。 ハンドラーはメモリー・ダンプの生成、例外が発生した場所のリストの表示、計算結果の変更、またはその他の 指定された処理の実行を行うことができます。
XL Fortran コンパイラーは、浮動小数点例外条件の処理に オペレーティング・システム機能を使用します。 これらの機能は、SIGFPE シグナルを生成することにより、浮動小数点例外の存在を示します。
XL Fortran の例外トラッピングをオンにするには、-qflttrap オプション、 および enable を含むサブオプションの組み合わせを指定して、 プログラムをコンパイルします。 このオプションはトラップ操作を使用して浮動小数点例外を検出し、 例外発生時に SIGFPE シグナルを 生成します。
-qflttrap は、例外条件の名前に対応するサブオプションも持っています。 たとえば、オーバーフローおよびアンダーフロー例外の処理のみに関心がある場合は、 次のように指定することができます。
xlf95 -qflttrap=overflow:underflow:enable compute_pi.fenable が必要なのは、メインプログラムをコンパイルするときだけですが、ただし、これは非常に 重要であり、他のファイルに対して指定しても何の問題も発生させないので、-qflttrap を使用する場合は、 常にこれを入れるようにしてください。
このアプローチの利点は、パフォーマンスの影響が比較的少なくなることです。 パフォーマンスの影響をさらに少なくするために、-qflttrap オプションの imprecise サブオプションを入れることができます。 これによって、プログラムがサブプログラムの始まりまたは終わりに達するまで、トラッピングが遅れます。
この方法の欠点は次のとおりです。
注:
重要: 浮動小数点演算の例外チェックを使用可能にする 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 には次のような例外ハンドラーと関連ルーチンがあります。
これらのハンドラー名のすべてに、 プログラム内で宣言した名前と重複しないよう 2 つの下線が付いています。 また、これらのルーチンはすべて SIGTRAP シグナルと SIGFPE シグナルの両方に対して機能します。
-g コンパイラー・オプションを使用すると、トレースバック・リスト内の行番号を知ることができます。 ファイル /opt/ibmcmp/xlf/9.1/include/fsignal.h では、 signal.h システム・ヘッダー 内の sigcontext 構造体に似ている Fortran 派生型が定義されています。 この派生型にアクセスする Fortran シグナル・ハンドラーを作成できます。
-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 サブルーチンを呼び出し、トラップを発生させる例外を指定します。
丸めモードの選択にある fpsets と fpgets を使用したサンプル・プログラムを 参照してください。
別の方法として、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 プロシージャーを使用すると、 浮動小数点状況とプロセッサーの制御レジスター (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 ランゲージ・リファレンス」の『サービス・ プロシージャーおよびユーティリティー・プロシージャー』の節を 参照してください。
サブルーチン 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 には、例外処理の異なる面を説明するために多くのサンプル・プログラムが入っています。
サンプル・プログラムは、例示することだけを目的にしています。
変数に「使用しない」というマークを付けるために、 変数内にシグナル NaN と呼ばれる特殊値をエンコードします。 それによって、計算でその変数が使用されるたびに、 効力のない例外条件を発生させることができます。
この手法を使用する場合は、シグナル NaN が使用されるすべてのケースを プログラムが正しく検出するように、-qfloat オプションの nans サブオプションを使用し、 対応する SIGFPE シグナルを 生成するための方法 (前述) のいずれかを使用してください。
注:
浮動小数点演算例外条件を処理したいが、プログラムがあまり遅くならないよう にしたい場合、以下にパフォーマンスへの影響を最小化するのに役立つ手法をいくつか示します。
xlf90 -qflttrap=underflow:enable:imprecise does_underflows.f
imprecise は、浮動小数点計算を実行するサブプログラムの入り口と出口でのみ、 指定された例外のチェックをプログラムに実行させます。 つまり、XL Fortran ではどのような例外も最終的には検出されます。 ただし、例外が発生したおよその位置はわかりますが、正確な位置ではありません。
imprecise を付けないで -qflttrap を指定すると、浮動小数点操作には、そのつど後に 例外チェックが続きます。 -qflttrap でコンパイルされていないルーチン (たとえばライブラリー・ルーチン) への呼び出し中に すべての例外が発生する場合、正確な位置を識別するのは難しいので、通常は imprecise を使用するのが よいでしょう。
nanq サブオプションを使用している場合、enable は効力を持たないことに注意してください。nanq は、imprecise が指定されている場合であっても、それぞれの浮動小数点数演算、 浮動小数点値を戻すロード命令およびプロシージャーの後でトラッピング・コードを生成します。