始めに述べたとおり、浮動小数点算術演算に関する IEEE 標準は、回避または回復に特別な注意が必要な多数の例外 (エラー) 条件を規定しています。以下の項は、このような例外条件が存在する中でプログラムを安全に作動させ、その一方で、犠牲にするパフォーマンスを最小にとどめるのに役立つ内容になっています。
浮動小数点ハードウェアは、常に多数の浮動小数点演算の例外条件 (これは、 IEEE 標準で厳格に規定されています) を検出します。たとえば、オーバーフロー、アンダーフロー、ゼロ除算、無効、および不正確さなどです。
デフォルト時には、とられるアクションは状況フラグの設定だけです。プログラムは問題なく処理を続行します (それ以降の結果は予測どおりでない場合もあります)。例外がいつ発生するかを知りたい場合は、シグナルを生成するように、これらの例外条件の内の 1 つまたは複数を調整することができます。
シグナルによってハンドラー・ルーチンへの分岐が生じます。シグナルが生じたときに、ハンドラーはシグナルのタイプとプログラムの状態についての情報を受け取ります。ハンドラーはメモリー・ダンプの生成、例外が発生した場所のリストの表示、計算結果の変更、またはその他の指定された処理の実行を行えます。
XL Fortran のコンパイラーにもオペレーティング・システムにも、浮動小数点演算例外条件の処理機能があります。コンパイラー機能は、SIGTRAP シグナルを生成して例外の存在を示します。オペレーティング・システム機能は、SIGFPE シグナルを生成します。これらの異なった機能を 1 つのプログラム内に混在させないでください。
XL Fortran の例外トラッピングをオンにするには、-qflttrap オプション、および enable を含むサブオプションの組み合わせを指定して、プログラムをコンパイルします。このオプションはトラップ操作を使用して浮動小数点例外を検出し、例外発生時に SIGTRAP シグナルを生成します。
-qflttrap は、例外条件の名前に対応するサブオプションも持っています。たとえば、オーバーフローおよびアンダーフロー例外の処理のみに関心がある場合は、次のように指定することができます。
xlf95 -qflttrap=overflow:underflow:enable compute_pi.fenable が必要なのは、メインプログラムをコンパイルするときだけですが、ただし、これは非常に重要であり、他のファイルに対して指定しても、何の問題も発生させないので、-qflttrap を使用する場合は、常にこれを入れるようにしてください。
このアプローチの利点は、パフォーマンスの影響が比較的少なくなることです。パフォーマンスの影響をさらに少なくするために、 -qflttrap オプションの imprecise サブオプションを入れることができます。これによって、プログラムがサブプログラムの初めか終わりに達するまで、トラップが遅れます。
この方法の欠点は次のとおりです。
注:
重要: 浮動小数点演算の例外チェックを使用可能にする fpsets 呼び出しがコードに入っているときに、 -qflttrap オプションを使用しないでプログラム全体をコンパイルすると、 表 18 に説明してあるように、例外発生時にプログラムは予期しない結果を発生させます。
例外トラップをオンにする直接的な方法は、オペレーティング・システム・ルーチン fp_trap を呼び出すことです。このルーチンはシステム・ハードウェアを使用して浮動小数点演算例外を検出し、例外が発生した場合に、SIGFPE シグナルを生成します。このオペレーティング・システム・ルーチンを呼び出すのに必要な値に関する Fortran 定義は、 /usr/include/fp_fort_c.f ファイル、fp_fort_t.f ファイル、または xlf_fp_util モジュールにあります。
fp_trap の説明を読めば見つけられる関連オペレーティング・システム・ルーチンは他にもあります。
この方法の利点は次のとおりです。
この方法の欠点は次のとおりです。
XL Fortran または AIX の例外検出機能を使用するプログラムは、例外条件を検出すると、シグナルを生成します。これによって、プログラムによってどのハンドラーが指定されていても、その指定されているハンドラーへの分岐が発生します。この節の情報は (-qsigtrap オプションの説明を除く)、SIGTRAP シグナルと SIGFPE シグナルの両方に適用されます。
デフォルト時には、プログラムはコア・ファイル (これをデバッガーとともに使用して問題を突き止めることができます) を作成してから停止します。 SIGTRAP シグナル・ハンドラーをインストールしたい場合は、-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 サブルーチン (/usr/include/fexcp.h に定義されます) を呼び出すことによって、XL Fortran が提供するものでも、自分が作成したものでも、代替の例外ハンドラーをインストールすることができます。
INCLUDE 'fexcp.h' CALL SIGNAL(SIGTRAP,handler_name) CALL SIGNAL(SIGFPE,handler_name)
XL Fortran には次のような例外ハンドラーと関連ルーチンがあります。
これらのハンドラー名のすべてに、プログラム内で宣言した名前と重複しないよう 2 つの下線が付いています。また、これらのルーチンはすべて SIGTRAP シグナルと SIGFPE シグナルの両方に対して機能します。
-g コンパイラー・オプションを使用すると、トレースバック・リスト内の行番号を知ることができます。ファイル /usr/include/fsignal.h では、/usr/include/sys/signal.h 内の sigcontext 構造体に似ている Fortran 派生型が定義されています。この派生型にアクセスする Fortran シグナル・ハンドラーを作成できます。
コア・ファイルを作成する場合は、例外ハンドラーをインストールしないか、 xl__trcedump ハンドラーを指定してください。
-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 配列 (インクルード・ファイル /usr/include/fpdc.h に定義されている) を操作して、 fpsets サブルーチンを呼び出し、トラップを発生させる例外を指定します。
丸めモードの選択にある fpsets と fpgets を使用したサンプル・プログラムを参照してください。
別の方法は、xlf_fp_util モジュールの中の set_fpscr_flags() サブルーチンを使用する方法です。このサブルーチンを使用すると、MASK 引き数で指定する浮動小数点状況と制御レジスター・フラグを設定することができます。 MASK で指定しないフラグは、そのままの状態になります。 MASK のタイプは、INTEGER(FPSCR_KIND) でなければなりません。たとえば、次のようになります。
USE 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.
xlf_fp_util プロシージャーを使用すると、浮動小数点状況とプロセッサーの制御レジスター (fpscr) を直接照会したり制御することができます。これらのプロシージャーは、浮動小数点状況と制御レジスターを直接操作するインライン機械命令にマップされるので、 fpsets および fpgets サブルーチンより効率的です。
モジュール xlf_fp_util には、これらのプロシージャーのインターフェースとデータ型定義と、プロシージャーで必要な名前付き定数の定義が入っています。このモジュールでは、これらのプロシージャーのタイプを、リンク時ではなくコンパイル時に検査することができます。モジュール xlf_fp_util には、以下のファイルが提供されています。
ファイル名 | ファイル・タイプ | 場所 |
---|---|---|
xlf_fp_util.mod | モジュール・シンボル・ファイル (32 ビット) |
|
モジュール・シンボル・ファイル (64 ビット) | /usr/lpp/xlf/include_64 | |
| モジュール・シンボル・ファイル (64 ビット LDT) | /usr/lpp/xlf/include_64ldt |
プロシージャーを使用するには、ソース・ファイルに USE XLF_FP_UTIL ステートメントを追加する必要があります。詳細については、「XL Fortran for AIX ランゲージ・リファレンス 」の「USE」を参照してください。
-U オプションを指定してコンパイルする場合は、これらのプロシージャーの名前をすべて小文字でコードする必要があります。
xlf_fp_util プロシージャーのリストについては、「XL Fortran for AIX ランゲージ・リファレンス 」の『サービス・プロシージャーおよびユーティリティー・プロシージャー 』の章を参照してください。
サブルーチン fpsets および fpgets は、浮動小数点状況レジスターの操作または照会を行う方法を提供します。オペレーティング・システム・ルーチンを直接呼び出す代わりに、
fpstat (論理値の配列) 内で情報をあちらこちらに渡します。次の表は、例外を処理する配列エレメントで、最もよく使用されるものを示しています。
表 20. 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) | 浮動小数点無効演算例外 (NaNS) |
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.
/usr/lpp/xlf/samples/floating_point には、例外処理の異なる面を説明するために多くのサンプル・プログラムが入っています。
サンプル・プログラムは、例示することだけを目的にしています。
変数に「使用しない」というマークを付けるために、変数内にシグナル NaN と呼ばれる特殊値をエンコードします。それによって、計算でその変数が使用されるたびに、効力のない例外条件を発生させることができます。
この手法を使用する場合は、シグナル NaN が使用されるすべてのケースをプログラムが正しく検出するように、-qfloat オプションの nans サブオプションを使用し、対応する |SIGFPE または SIGTRAP シグナルを生成するための方法 (前述) のいずれかを使用してください。
注:
浮動小数点演算例外を処理する場合でも、処理によってプログラムがあまり遅くならないようにする手法を以下にいくつか示します。
xlf90 -qflttrap=underflow:enable:imprecise does_underflows.f
imprecise は、浮動小数点計算を実行するサブプログラムの入り口と出口でのみ、指定された例外のチェックをプログラムに実行させます。つまり、XL Fortran ではどんな例外も最終的には検出されます。ただし、例外が発生したおよその位置はわかりますが、正確な位置ではありません。
imprecise を付けないで -qflttrap を指定すると、浮動小数点操作には、そのつど後に例外チェックが続きます。 -qflttrap でコンパイルされていないルーチン (たとえばライブラリー・ルーチン) への呼び出し中にすべての例外が発生する場合、正確な位置を識別するのは難しいので、通常は imprecise を使用するのがよいでしょう。