Oracle Solaris Studio コンパイラ製品は、Solaris 10 オペレーティング環境内のヘッダーファイルやライブラリとともに、System V Interface Definition Edition 3 (SVID)、X/Open、ANSI C (C90)、POSIX.1-2001 (SUSv3)、ISO C (C99) を含む複数の標準規格をサポートしています。 (詳細は、standards(5) を参照してください。) これらの標準規格の中には、特定の点で実装の相違が認められるものがあります。場合によっては、これらの標準の仕様が矛盾することもあります。数学ライブラリの場合、これらの相違点や矛盾は主に、特殊なケースおよび例外に関連しています。この付録では、libm に含まれる関数の動作を示し、C プログラムがどのような条件でそれぞれの標準規格に準拠するよう動作するかについて説明します。この付録の最後のセクションでは、Sun Studio C および Fortran 言語製品の LIA-1 への準拠について説明します。
Table E–1 は、上で挙げた標準規格の 2 つ以上が libm 内の関数に対して矛盾する動作を指定するすべてのケースを示しています。C プログラムがどの動作に準拠するかは、そのプログラムをコンパイルし、リンクするときに使用されるコンパイラフラグによって異なります。考えられる動作としては、浮動小数点例外を発生させる、発生した特殊なケースに関する情報と返される値を指定してユーザー提供の関数 matherr を呼び出す (matherr(3M) を参照)、メッセージを標準エラーファイルに出力する、大域変数を設定する errno (intro(2) および perror(3C) を参照) などがあります。
Table E–1 の最初の列は、特殊なケースを定義しています。2 番目の列は、errno に設定される値を示しています (設定される場合)。errno の可能性のある値は、<errno.h> で定義されています。数学ライブラリで使用される値は、ドメインエラーを示す EDOM と、範囲エラーを示す ERANGE の 2 つだけです。2 番目の列に EDOM と ERANGE の両方が示されている場合、errno に設定される値は、この後に説明するとおり標準規格で決定され、4 番目と 5 番目の列に示されます。3 番目の列は、エラーメッセージが出力される場合に示されるエラーコードを示しています。4 番目、5 番目、および 6 番目の列は、さまざまな標準規格の定義に従って名目上返される関数値を示しています。場合によっては、ユーザー提供の matherr ルーチンがこれらの値をオーバーライドし、別の戻り値を提供することがあります。
これらの特殊なケースへの具体的な対応は、次のようにプログラムがリンクされるときに指定されたコンパイラフラグによって決定されます。–xlibmieee または –xc99=lib のどちらかが指定されている場合は、Table E–1 の特殊なケースが発生すると、いずれかの該当する浮動小数点例外が発生し、表の 6 番目の列に示されている関数値が返されます。
–xlibmieee と –xc99=lib のどちらも使用されていない場合、動作は、プログラムがリンクされるときに指定された言語準拠フラグによって異なります。
-Xa フラグを指定すると、X/Open 準拠が選択されます。表にあるいずれかの特殊なケースが発生すると、いずれかの該当する浮動小数点例外が発生し、errno が設定され、表の 5 番目の列に示されている関数値が返されます。ユーザー定義の matherr ルーチンが提供されている場合、動作は定義されていません。–Xa は、ほかの言語準拠フラグが指定されていないときのデフォルトです。
-Xc フラグを指定すると、厳格な C90 準拠が選択されます。特殊なケースが発生すると、いずれかの該当する浮動小数点例外が発生し、errno が設定され、表の 5 番目の列に示されている関数値が返されます。この場合、matherr は呼び出されません。
最後に、–Xs または –Xt フラグのどちらかを指定すると、SVID 準拠が選択されます。特殊なケースが発生すると、いずれかの該当する浮動小数点例外が発生し、matherr が呼び出されます。matherr が 0 を返した場合は、errno が設定され、エラーメッセージが出力されます。表の 4 番目の列に示されている関数値は、それが matherr によってオーバーライドされないかぎり返されます。
–xc99、–Xa、–Xc、–Xs、および –Xt フラグの詳細は、cc(1) のマニュアルページおよびOracle Solaris Studio 12.4: C ユーザーガイド を参照してください。
|
注:
HUGE は、<math.h> で定義されています。SVID では、HUGE が MAXFLOAT (約 3.4e+38) に等しくなる必要があります。
HUGE_VAL は、<math.h> に含まれている <iso/math_iso.h> で定義されています。HUGE_VAL は、無限大に評価されます。
X_TLOSS は、<values.h> で定義されています。
上に挙げたコンパイラフラグは、Table E–1 に示されている特殊なケースを処理する場合に、いくつかの標準規格のうちのどれに従うかを直接選択します。その他のコンパイラフラグには、前に説明した動作をプログラムが準拠するかどうかに間接的に影響するものもあります。
まず、–xlibmil と –xlibmopt はどちらも libm 内の一部の関数をより高速な実装に置き換えます。これらの高速な実装は、SVID、X/Open、または C90 に準拠していません。また、errno の設定や matherr の呼び出しも行いません。ただし、必要に応じて浮動小数点例外を発生させたり、IEEE 754 または C99、あるいはその両方で指定されている結果を生成したりします。–xvector フラグにも同じことが当てはまります。このフラグによって、コンパイラが標準数学関数の呼び出しをベクトル数学関数の呼び出しに変換することがあるためです。
2 番目に、–xbuiltin フラグにより、コンパイラは <math.h> で定義されている標準数学関数を組み込み関数として扱い、パフォーマンスを向上させるためにインラインコードに置き換えることができます。置き換えたコードは、SVID、X/Open、C90、または C99 に準拠していない場合があります。errno を設定したり、matherr を呼び出したり、浮動小数点例外を発生させたりする必要はありません。
3 番目に、C プリプロセッサトークン __MATHERR_ERRNO_DONTCARE が定義されていると、<math.h> 内のいくつかの #pragma ディレクティブがコンパイルされます。これらのディレクティブは、標準数学関数に副次的影響がないと仮定するようコンパイラに指示します。この仮定の下では、数学関数の呼び出し、errno などの大域データへの参照、ユーザー提供の matherr ルーチンで変更されている可能性のあるデータの順序がコンパイラによって変更され、前述の予測される動作に反する可能性があります。たとえば、次のコードフラグメントについて考えてみます。
#include <errno.h> #include <math.h> ... errno = 0; x = acos(2.0); if (errno) { printf(“error\n”); }
__MATHERR_ERRNO_DONTCARE を定義してこのコードをコンパイルすると、コンパイラは errno が acos の呼び出しによって変更されないと仮定し、それに応じてコードを変換するため、printf の呼び出しを完全に削除する可能性があります。
–fast マクロフラグには、フラグ –xbuiltin、–xlibmil、–xlibmopt、および –D__MATHERR_ERRNO_DONTCARE が含まれることに注意してください。
最後に、libm 内のすべての数学関数が必要に応じて浮動小数点例外を発生させるため、通常、これらの例外に対するトラップを有効にしてプログラムを実行すると、前述の標準規格で指定されているものとは異なる動作が実行されます。そのため、–ftrap コンパイラフラグも標準規格への準拠に影響を及ぼす場合があります。
C99 では、Table E–1 に示すような特殊なケースを実装によって処理できると想定される方法が 2 つ規定されています。1 つの実装は、値 MATH_ERRNO (1) または MATH_ERREXCEPT (2)、あるいはこのビット単位の「論理和」を持つ整数式を評価する識別子 math_errhandling を定義することによって、2 つの方法のどちらをサポートするかを示します。(これらの値は、<math.h> で定義されています) 式 (math_errhandling & MATH_ERRNO) が 0 以外である場合、実装では errno を EDOM に設定することによって、関数の引数がその数学的ドメインの外側に存在するケースを処理し、errno を ERANGE に設定することによって、関数の結果値がアンダーフローする、オーバーフローする、または正確に無限大に等しくなるケースを処理します。式 (math_errhandling & MATH_ERREXCEPT) が 0 以外である場合、実装では無効な演算例外を発生させることによって、関数の引数がその数学的ドメインの外側に存在するケースを処理し、アンダーフロー、オーバーフロー、またはゼロ除算の例外を発生させることによって、それぞれ、関数の結果値がアンダーフローする、オーバーフローする、または正確に無限大に等しくなるケースを処理します。
Oracle Solaris では、<math.h> は、math_errhandling を MATH_ERREXCEPT として定義します。Table E–1 に示す関数は、そこに示す特殊なケースに対して別のアクションを実行する可能性がありますが、float および long double 関数、複素関数、C99 で指定されているその他の関数を含め、すべての libm 関数が浮動小数点例外を発生させることによって特殊なケースに対応します。これは、すべての C99 関数対して一貫してサポートされている特殊ケースを処理するための唯一の方法です。
最後に、C99 または SUSv3 のどちらの場合でも、Oracle Solaris のデフォルトとは異なる動作が要求される 3 つの関数が存在することに注意してください。これらの相違点を次の表にまとめます。この表には、各関数の double バージョンのみを示していますが、これらの相違点は float および long double バージョンにも同様に適用されます。いずれのケースでも、プログラムが -xc99=lib でリンクされている場合は SUSv3 の仕様に従い、それ以外の場合は Solaris のデフォルトに従います。
|
このセクションでは、LIA-1 は「ISO/IEC 10967-1:1994 Information Technology - Language Independent Arithmetic - Part 1: Integer and floating-point arithmetic」を指します。
Sun Studio コンパイラのリリースに含まれている C および Fortran 95 コンパイラ (cc および f95) は、次の点で LIA-1 に準拠しています (段落の文字は LIA-1 のセクション 8 の文字に対応しています)。
LIA-1 準拠のデータ型は、C の int と Fortran の INTEGER です。その他のデータ型の準拠もありますが、ここでは規定されていません。特定の言語に対するそれ以上の仕様は、管轄している言語標準規格の組織から LIA-1 への言語バインディング待ちです。
#include <values.h> /* defines MAXINT */ #define TRUE 1 #define FALSE 0 #define BOUNDED TRUE #define MODULO TRUE #define MAXINT 2147483647 #define MININT ‐2147483648 logical bounded, modulo integer maxint, minint parameter (bounded = .TRUE.) parameter (modulo = .TRUE.) parameter (maxint = 2147483647) parameter (minint = ‐2147483648)
C の / と %、および Fortran の / と mod() によって、DIVtI(x,y) と REMtI(x,y) が提供されます。また、modaI(x,y) も次のコードで使用できます。
int modaI(int x, int y) { int t = x % y; if (y < 0 && t > 0) t ‐= y; else if (y > 0 && t < 0) t += y; return t; }
これは、次のコードでも使用できます。
integer function modaI(x, y) integer x, y, t t = mod(x, y) if (y .lt. 0 .and. t .gt. 0) t = t ‐ y if (y .gt. 0 .and. t .lt. 0) t = t + y modaI = t return end
次の表は、LIA の整数演算で認識される表記法を示しています。
|
次のコードは、signI(x) の Fortran での表記法を示しています。
integer function signi(x) integer x, t if (x .gt. 0) t=1 if (x .lt. 0) t=‐1 if (x .eq. 0) t=0 return end
デフォルトでは、最適化が指定されていない場合、式は int (C) または INTEGER (Fortran) の精度で評価されます。括弧も同様です。a + b + c や a * b * c などの、括弧で囲まれていない連結した式の評価順序は規定されていません。
ソースコード内の b.パラメータ (LIA 5.1):に定義が含まれています。
整数の例外は、x/0 と x%0、または mod(x,0) です。デフォルトでは、これらの例外によって SIGFPE が生成されます。SIGFPE に対してシグナルハンドラが指定されていない場合は、プロセスが終了し、メモリーがダンプされます。
signal(3) または signal(3F) を使用すると、SIGFPE に対するユーザー例外処理を有効にすることができます。