このセクションでは、C99 の <fenv.h> 浮動小数点環境関数について説明します。Oracle Solaris 10 OS では、これらの関数は libm で使用できます。これらは ieee_flags 関数と同じ機能の多くを提供しますが、より自然な C インタフェースを使用しており、また C99 で定義されているために移植性も高くなります。
fenv.h ファイルは、FE_INEXACT、FE_UNDERFLOW、FE_OVERFLOW、FE_DIVBYZERO、FE_INVALID という 5 つの各 IEEE 浮動小数点例外フラグのためのマクロを定義します。さらに、マクロ FE_ALL_EXCEPT は、5 つのすべてのフラグマクロのビット単位の「or」として定義されています。以降の説明で、excepts パラメータは、5 つのいずれかのフラグマクロのビット単位の「or」か、または値 FE_ALL_EXCEPT のどちらかです。fegetexceptflag および fesetexceptflag 関数の場合、flagp パラメータは、型 fexcept_t のオブジェクトへのポインタである必要があります。この型は、fenv.h で定義されています。
C99 では、次の表にある例外フラグ関数が定義されています。
|
feclearexcept 関数は、指定されたフラグをクリアします。fetestexcept 関数は、設定されている excepts 引数によって指定されたフラグのサブセットに対応するマクロ値のビット単位の「or」を返します。たとえば、不正確、アンダーフロー、および 0 による除算のフラグだけが現在設定されている場合は、次の式によって i が FE_DIVBYZERO に設定されます。
i = fetestexcept(FE_INVALID | FE_DIVBYZERO);
feraiseexcept 関数は、指定された例外のトラップのいずれかが有効になっている場合はトラップを発生させます。それ以外の場合は、単に対応するフラグを設定します。例外トラップの詳細は、例外と例外処理を参照してください。
fegetexceptflag および fesetexceptflag 関数は、特定のフラグの状態を一時的に保存し、あとで復元するための便利な方法を提供します。特に、fesetexceptflag 関数はトラップを発生させず、単に指定されたフラグの値を復元します。
fenv.h ファイルは、FE_TONEAREST、FE_UPWARD (正の無限大に向けて)、FE_DOWNWARD (負の無限大に向けて)、FE_TOWARDZERO という 4 つの各 IEEE 丸め方向モードのためのマクロを定義します。C99 では、丸め方向モードを制御するための 2 つの関数が定義されています。fesetround は、現在の丸め方向を引数 (上の 4 つのマクロのいずれかである必要があります) によって指定された方向に設定し、fegetround は現在の丸め方向に対応するマクロの値を返します。
x86 ベースのシステムでは、fenv.h ファイルは、FE_FLTPREC (単精度)、FE_DBLPREC (倍精度)、FE_LDBLPREC (拡張倍精度) という 3 つの各丸め精度モードのためのマクロを定義します。C99 には含まれていませんが、x86 上の libm は、丸め精度モードを制御するための 2 つの関数を提供します。fesetprec は、現在の丸め精度を引数 (上の 3 つのマクロのいずれかである必要があります) によって指定された精度に設定し、fegetprec は現在の丸め精度に対応するマクロの値を返します。
fenv.h ファイルは、例外フラグ、丸め制御モード、例外処理モード、SPARC 上の非標準モードなどの、浮動小数点環境全体を表すデータ型 fenv_t を定義します。以降の説明で、envp パラメータは、型 fenv_t のオブジェクトへのポインタである必要があります。
C99 では、浮動小数点環境を操作するための 4 つの関数が定義されています。libm は、マルチスレッドプログラムで役立つ場合がある追加の関数を提供します。次の表に、これらの関数の要約を示します。
|
fegetenv および fesetenv 関数はそれぞれ、浮動小数点環境を保存および復元します。fesetenv への引数には、fegetenv または feholdexcept の呼び出しで以前に保存された環境へのポインタか、あるいは fenv.h で定義されている定数 FE_DFL_ENV のどちらかを指定できます。後者は、デフォルトの環境を表します。この環境では、すべての例外フラグがクリアされ、丸めがもっとも近い値に、また x86 ベースのシステム上では拡張倍精度に設定され、無停止例外処理モード (つまり、トラップが無効) と非標準モードが無効になっています。
feholdexcept 関数は現在の環境を保存してから、すべての例外フラグをクリアし、すべての例外に対して無停止例外処理モードを確立します。feupdateenv 関数は保存された環境 (これは、fegetenv または feholdexcept の呼び出しで保存された環境、あるいは定数 FE_DFL_ENV のどちらかです) を復元してから、以前の環境でフラグが設定されていた例外を発生させます。復元された環境で、これらの例外のいずれかに対してトラップが有効になっている場合はトラップが発生し、そうでない場合はフラグが設定されます。これらの 2 つの関数を組み合わせて使用すると、次のコーディング例に示すように、サブルーチン呼び出しを例外に関して不可分な動作に見せることができます。
#include <fenv.h> void myfunc(...) { fenv_t env; /* save the environment, clear flags, and disable traps */ feholdexcept(&env); /* do a computation that may incur exceptions */ ... /* check for spurious exceptions */ if (fetestexcept(...)) { /* handle them appropriately and clear their flags */ ... feclearexcept(...); } /* restore the environment and raise relevant exceptions */ feupdateenv(&env); }
fex_merge_flags 関数は、保存された環境から現在の環境への例外フラグの論理的な OR を、どのトラップも発生させることなく実行します。この関数をマルチスレッドプログラムで使用すると、子スレッドで計算によって設定されたフラグに関する親スレッド内の情報を保持できます。fex_merge_flags の使用を示す例については、例を参照してください。