Oracle® Solaris Studio 12.4: 数値計算ガイド

印刷ビューの終了

更新: 2015 年 1 月
 
 

4.5 例外の処理

歴史的に、ほとんどの数値計算ソフトウェアは例外を考慮せずに作成されてきており、多くのプログラマは、例外が発生するとプログラムがただちに中止するという環境に慣れていました。LAPACK などの高品質なソフトウェアパッケージでは、0 による除算や無効な演算などの例外を回避し、入力を積極的に位取りしてオーバーフローや結果が不正確になる可能性のあるアンダーフローを除外するように注意深く設計されています。例外を処理するためのこれらの方法はいずれも、あらゆる状況で適切であるわけではありません。ただし、例外を無視すると、あるプログラマが記述したプログラムやサブルーチンを (たとえば、ソースコードにアクセスできない) ほかのプログラマが使用する場合に、問題となることがあります。すべての例外を回避しようとすると、それに対応するための多くのテストと分岐が必要になり、非常に手間がかかる可能性があります。詳細は、『Faster Numerical Algorithms via Exception Handling』、Demmel、Li 共著、IEEE Trans. Comput. 43 発行 (1994 年) の 983–992 ページを参照してください。

第 3 の選択肢として、IEEE 算術演算のデフォルトの例外応答、ステータスフラグ、およびオプションのトラップ機能によって、例外が発生しても計算を続行してあとで例外を検出するか、発生時に割り込んで処理できます。前述のように、ieee_flags や C99 浮動小数点環境関数を使用してあとで例外を検出したり、ieee_handlerfex_set_handling を使用してトラップを有効にし、例外が発生したときにそれに割り込む SIGFPE ハンドラをインストールできます。ただし、計算を続行するために、IEEE 規格では、例外の原因となった演算の結果をトラップハンドラが提供できるようにすることを推奨しています。FEX_SIGNAL モードで ieee_handler または fex_set_handling を介してインストールされる SIGFPE ハンドラは、Solaris オペレーティング環境がシグナルハンドラに渡す uap パラメータを使用してこれを実現しています。fex_set_handling を介してインストールされる FEX_CUSTOM モードハンドラは、このようなハンドラに渡される info パラメータを使用して結果を提供できます。

C では、SIGFPE シグナルハンドラを次のように宣言できます。

#include <siginfo.h>
#include <ucontext.h>
 
void handler(int sig, siginfo_t *sip, ucontext_t *uap)
{
    ...
}

トラップされた浮動小数点例外の結果として SIGFPE シグナルハンドラが呼び出されると、uap パラメータは、そのマシンの整数レジスタおよび浮動小数点レジスタのコピー、およびその他の例外が記述されているシステム依存の情報が含まれているデータ構造体を指します。このシグナルハンドラが正常に返されると、保存されたデータが復元され、トラップが行われた箇所からプログラムの実行が再開されます。このように、例外を記述したデータ構造体の情報にアクセスして復号化し、可能であれば保存されたデータを変更することによって、SIGFPE ハンドラは例外演算の結果をユーザーが指定した値に置換して計算を続行できます。

FEX_CUSTOM モードハンドラは、次のように宣言できます。

#include <fenv.h>
 
void handler(int ex, fex_info_t *info)
{
    ...
}

FEX_CUSTOM ハンドラが呼び出されるとき、ex パラメータは発生した例外のタイプ (Table 4–4 に示されている値の 1 つ) を示し、info パラメータはその例外の詳細情報を含むデータ構造を指します。具体的には、このデータ構造には、例外の発生原因である算術演算を表すコードと、オペランドを記録する構造体 (利用できる場合) が含まれています。また、例外がトラップされなかった場合に置換されていたはずのデフォルトの結果を記録する構造体、および累積されたはずの例外フラグのビット単位の「or」を保持する整数値も含まれています。ハンドラは、構造体の後者のメンバーを変更して異なる結果に置き換えたり、累積された一連のフラグを変更したりできます。(これらのデータを変更せずにハンドラが戻った場合、プログラムは、例外がトラップされなかったかのように、デフォルトのトラップされていない結果とフラグを使用して続行します)。

次のセクションでは、アンダーフローまたはオーバーフローになる演算を位取りされた結果に置換する方法を示します。その他の例については、Appendix A, 例を参照してください。