Oracle® Developer Studio 12.5: 数値計算ガイド

印刷ビューの終了

更新: 2016 年 6 月
 
 

3.4 IEEE サポート関数

このセクションでは、IEEE で推奨される関数、役立つ値を提供する関数、ieee_flagsieee_retrospective、および standard_arithmeticnonstandard_arithmetic について説明します。関数 ieee_flagsieee_handler の詳細は、例外と例外処理を参照してください。

3.4.1 ieee_functions(3m) および ieee_sun(3m)

ieee_functions(3m) および ieee_sun(3m) で説明される関数は、IEEE 規格に必要な機能か、またはその付録で推奨されている機能を提供します。これらは、効率的なビットマスク演算として実装されます。

表 18  ieee_functions(3m)
関数
説明
math.h
ヘッダーファイル
copysign(x,y)
y の符号ビットを持つ x
fabs(x)
x の絶対値
fmod(x, y)
y を基準にした x の剰余
ilogb(x)
x の基数 2 のバイアスなし指数 (整数形式)
nextafter(x,y)
方向 y への x のあとの次の表現可能な数値
remainder(x,y)
y を基準にした x の剰余
scalbn(x,n)
x × 2n
表 19  ieee_sun(3m)
関数
説明
sunmath.h
ヘッダーファイル
fp_class(x)
分類関数
isinf(x)
分類関数
isnormal(x)
分類関数
issubnormal(x)
分類関数
iszero(x)
分類関数
signbit(x)
分類関数
nonstandard_arithmetic(void)
非標準モードの有効化
standard_arithmetic(void)
標準モードの有効化
ieee_retrospective(*f)
n/a

remainder(x,y) は、IEEE 規格 754-1985 で指定された演算です。remainder(x,y)fmod(x,y) の違いは、remainder(x,y) によって返される結果の符号が x または y のどちらかの符号と一致しない可能性があるのに対して、fmod(x,y) は常に、符号が x と一致する結果を返す点にあります。どちらの関数も正確な結果を返し、不正確の例外を生成しません。

表 20  Fortran からの ieee_functions の呼び出し
IEEE 関数
単精度
倍精度
4 倍精度
copysign(x,y)
t=r_copysign(x,y)
z=d_copysign(x,y)
z=q_copysign(x,y)
ilogb(x)
i=ir_ilogb(x)
i=id_ilogb(x)
i=iq_ilogb(x)
nextafter(x,y)
t=r_nextafter(x,y)
z=d_nextafter(x,y)
z=q_nextafter(x,y)
scalbn(x,n)
t=r_scalbn(x,n)
z=d_scalbn(x,n)
z=q_scalbn(x,n)
signbit(x)
i=ir_signbit(x)
i=id_signbit(x)
i=iq_signbit(x)
表 21  Fortran からの ieee_sun の呼び出し
IEEE 関数
単精度
倍精度
4 倍精度
signbit(x)
i=ir_signbit(x)
i=id_signbit(x)
i=iq_signbit(x)

注 -  次の関数を使用する Fortran プログラムでは、d_function を倍精度として、q_function を REAL*16 として宣言する必要があります。

3.4.2 ieee_values(3m)

無限大、NaN、最大と最小の正の浮動小数点数などの IEEE 値は、ieee_values(3m) のマニュアルページで説明されている関数によって提供されます。 表 22表 23表 24、および表 25 は、ieee_values(3m) 関数によって提供される値の 10 進数値と 16 進数の IEEE 表現を示しています。

表 22  IEEE 値: 単精度
IEEE 値
10 進数値の 16 進表現
C、C++、Fortran
最大の正規数
3.40282347e+38 7f7fffff
r = max_normalf(); r = r_max_normal()
最小の正規数
1.17549435e–38 00800000
r = min_normalf(); r = r_min_normal()
最大の非正規数
1.17549421e–38 007fffff
r = max_subnormalf(); r = r_max_subnormal()
最小の非正規数
1.40129846e–45 00000001
r = min_subnormalf(); r = r_min_subnormal()
Infinity 7f800000
r = infinityf(); r = r_infinity()
シグナルを発生しない NaN
NaN 7fffffff
r = quiet_nanf(0); r = r_quiet_nan(0)
シグナルを発生する NaN
NaN 7f800001
r = signaling_nanf(0); r = r_signaling_nan(0)
表 23  IEEE 値: 倍精度
IEEE 値
10 進数値の 16 進表現
C、C++、Fortran
最大の正規数
1.7976931348623157e+308
7fefffff ffffffff
d = max_normal(); d = d_max_normal()
最小の正規数
2.2250738585072014e–308
00100000 00000000
d = min_normal(); d = d_min_normal()
最大の非正規数
2.2250738585072009e–308
000fffff ffffffff
d = max_subnormal(); d = d_max_subnormal()
最小の非正規数
4.9406564584124654e–324
00000000 00000001
d = min_subnormal(); d = d_min_subnormal()
Infinity
7ff00000 00000000
d = infinity(); d = d_infinity()
シグナルを発生しない NaN
NaN
7fffffff ffffffff
d = quiet_nan(0); d = d_quiet_nan(0)
シグナルを発生する NaN
NaN
7ff00000 00000001
d = signaling_nan(0); d = d_signaling_nan(0)
表 24  IEEE 値: 4 倍精度
IEEE 値
10 進数値の 16 進表現
C、C++ (SPARC)
Fortran (すべて)
最大の正規数
1.1897314953572317650857593266280070e+4932
7ffeffff ffffffff ffffffff ffffffff
q = max_normall(); q = q_max_normal()
最小の正規数
3.3621031431120935062626778173217526e–4932
00010000 00000000 00000000 00000000
q = min_normall(); q = q_min_normal()
最大の非正規数
3.3621031431120935062626778173217520e–4932
0000ffff ffffffff ffffffff ffffffff
q = max_subnormall(); q = q_max_subnormal()
最小の非正規数
6.4751751194380251109244389582276466e–4966
00000000 00000000 00000000 00000001
q = min_subnormall(); q = q_min_subnormal()
Infinity
7fff0000 00000000 00000000 00000000
q = infinityl(); q = q_infinity()
シグナルを発生しない NaN
NaN
7fff8000 00000000 00000000 00000000
q = quiet_nanl(0); q = q_quiet_nan(0)
シグナルを発生する NaN
NaN
7fff0000 00000000 00000000 00000001
q = signaling_nanl(0); q = q_signaling_nan(0)
表 25  IEEE 値: 拡張倍精度 (x86)
IEEE 値
10 進数値の 16 進表現 (80 ビット)
C、C++
最大の正規数
1.18973149535723176505e+4932
7ffe ffffffff ffffffff
x = max_normall();
最小の正の正規数
3.36210314311209350626e–4932
0001 80000000 00000000
x = min_normall();
最大の非正規数
3.36210314311209350608e–4932
0000 7fffffff ffffffff
x = max_subnormall();
最小の正の非正規数
1.82259976594123730126e–4951
0000 00000000 00000001
x = min_subnormall();
Infinity
7fff 80000000 00000000
x = infinityl();
シグナルを発生しない NaN
NaN
7fff c0000000 00000000
x = q
シグナルを発生する NaN
NaN
7fff 80000000 00000001
x = signaling_nanl(0);

3.4.3 ieee_flags(3m)

ieee_flags (3m) は、次のための Oracle インタフェースです。

  • 丸め方向モードの問い合わせまたは設定

  • 丸め精度モードの問い合わせまたは設定

  • 例外発生フラグの検査、クリア、または設定

ieee_flags(3m) を呼び出すための構文は次のとおりです。

i = ieee_flags(action, mode, in, out);

パラメータに指定できる値の ASCII 文字列を表 26 に示します。

表 26  ieee_flags のパラメータ値
パラメータ
C または C++ の型
指定できるすべての値
action
char *
getsetclearclearall
mode
char *
directionprecisionexception
in
char *
nearesttozeronegativepositiveextendeddoublesingleinexactdivisionunderflowoverflowinvalidallcommon
out
char **
nearesttozeronegativepositiveextendeddoublesingleinexactdivisionunderflowoverflowinvalidallcommon

ieee_flags(3m) のマニュアルページでは、これらのパラメータが詳細に説明されています。

ieee_flags を使用して変更できる演算機能のいくつかについては、次の段落で説明します。第 4 章には、ieee_flags と IEEE 例外フラグに関する詳細情報が含まれています。

modedirection である場合は、指定されたアクションが現在の丸め方向に適用されます。指定できる丸め方向は、もっとも近い値に向けた丸め、0 に向けた丸め、+· に向けた丸め、または -· に向けた丸めです。IEEE のデフォルトの丸め方向は、もっとも近い値に向けた丸めです。つまり、演算の数学的な結果が 2 つの隣接する表現可能な数値の間に厳密に存在する場合、数学的な結果にもっとも近い数値が提供されます。(数学的な結果が 2 つのもっとも近い表現可能な数値の正確に中央に存在する場合、提供される結果は最下位ビットが 0 である数値です。この点を強調するために、もっとも近い値に向けた丸めモードは、もっとも近い偶数値への丸めと呼ばれる場合があります。)

0 に向けた丸めは、IEEE が現れる以前の多くのコンピュータの動作方法であり、数学的には結果の切り捨てに対応しています。 たとえば、2/3 が 10 進数 6 桁に丸められた場合の結果は、丸めモードがもっとも近い値に向けた丸めであるときは .666667 ですが、丸めモードが 0 に向けた丸めであるときは .666666 です。

ieee_flags を使用して丸め方向を検査、クリア、または設定する場合に、4 つの入力パラメータに指定できる値を表 27 に示します。

表 27  丸め方向に関する ieee_flags の入力値
パラメータ
指定できる値 (モードは direction)
action
getsetclearclearall
in
nearesttozeronegativepositive
out
nearesttozeronegativepositive

modeprecision である場合は、指定されたアクションが現在の丸め精度に適用されます。x86 ベースのシステムでは、指定できる丸め精度は単精度、倍精度、および拡張です。デフォルトの丸め精度は拡張です。このモードでは、結果を x87 浮動小数点レジスタに渡す算術演算は、その結果を拡張倍精度レジスタ形式の完全な 64 ビット精度に丸めます。丸め精度が単精度または倍精度である場合、結果を x87 浮動小数点レジスタに渡す算術演算は、その結果をそれぞれ 24 または 53 の上位ビットに丸めます。ほとんどのプログラムは少なくとも同程度に正確な結果を生成しますが、拡張の丸め精度が使用されている場合、IEEE 演算のセマンティクスへの厳格な遵守が必要な一部のプログラムは拡張の丸め精度モードでは正しく機能しないため、必要に応じて、単精度または倍精度に設定された丸め精度で実行する必要があります。

丸め精度は、SPARC プロセッサを使用したシステム上では設定できません。これらのシステムでは、mode = precisionieee_flags を呼び出しても計算には影響を与えません。

最後に、modeexception である場合は、指定されたアクションが現在の IEEE 例外フラグに適用されます。ieee_flags を使用して IEEE 例外フラグを検査したり、制御したりする方法の詳細は、例外と例外処理を参照してください。

3.4.4 ieee_retrospective(3m)

libsunmath 関数である ieee_retrospective は、未処理の例外および非標準の IEEE モードに関する情報を出力します。次の内容が報告されます。

  • 未処理の例外。

  • 有効になっているトラップ。

  • 丸め方向または精度がデフォルト以外に設定されているかどうか。

  • 非標準の演算が有効かどうか。

必要な情報は、ハードウェア浮動小数点ステータスレジスタから取得されます。

ieee_retrospective は、設定された例外フラグ、およびトラップが有効になっている例外に関する情報を出力します。これらの 2 つの (関連はしていても) 個別の情報を混同しないでください。例外フラグが設定されている場合は、プログラム実行中のある時点でその例外が発生しました。例外に対してトラップが有効になっている場合は、その例外はまだ実際に発生していない可能性がありますが、発生している場合は、SIGFPE シグナルが提供されています。ieee_retrospective メッセージは、例外フラグが設定されている場合は、調査を必要としている可能性がある例外についてユーザーに警告すること、また例外のトラップが有効になっている場合は、その例外がシグナルハンドラによって処理された可能性がある点をユーザーに知らせることを目的にしています。例外と例外処理では、例外、シグナル、およびトラップについて説明するとともに、発生した例外の原因を調査する方法を示しています。

プログラムは、いつでも ieee_retrospective を明示的に呼び出すことができます。–f77 互換モードの f95 でコンパイルされた Fortran プログラムは、自動的に ieee_retrospective を呼び出してから終了します。デフォルトモードの f95 でコンパイルされた C/C++ プログラムおよび Fortran プログラムは、自動的に ieee_retrospective を呼び出しません。

ただし、f95 コンパイラは共通例外に対するトラップをデフォルトで有効にするため、プログラムがトラップを明示的に無効にするか、または SIGFPE ハンドラをインストールしないかぎり、このような例外が発生するとプログラムがただちに異常終了することに注意してください。–f77 互換モードでは、コンパイラがトラップを有効にしないため、浮動小数点例外が発生してもプログラムは実行を継続し、終了時に ieee_retrospective 出力でこれらの例外を報告します。

この関数を呼び出すための構文は次のとおりです

  • C、C++ - ieee_retrospective(fp);

  • Fortran - call ieee_retrospective()

C 関数の場合、引数 fp は、出力が書き込まれるファイルを指定します。Fortran 関数は、常に出力を stderr に出力します。

次の例は、ieee_retrospective の 6 つの警告メッセージのうちの 4 つを示しています。

Note: IEEE floating-point exception flags raised:
   Inexact; Underflow; 
Rounding direction toward zero 
IEEE floating-point exception traps enabled: 
   overflow; 
See the Numerical Computation Guide, ieee_flags(3M), 
ieee_handler(3M), ieee_sun(3m)

警告メッセージは、トラップが有効になっているか、または例外が発生した場合にのみ表示されます。

ieee_retrospective メッセージは、Fortran プログラムから 3 つの方法のいずれかで抑制できます。 1 つの方法は、プログラムが終了する前に、未処理の例外をすべてクリアし、トラップを無効にして、もっとも近い値への丸め、拡張精度、および標準モードに戻す方法です。これを行うには、ieee_flagsieee_handler、および standard_arithmetic を次のように呼び出します。

character*8 out 
i = ieee_flags('clearall', '', '', out) 
call ieee_handler('clear', 'all', 0)
call standard_arithmetic()

注 -  未処理の例外を、その原因を調査せずにクリアすることはお勧めできません。

ieee_retrospective メッセージが表示されないようにするための別の方法は、stderr のファイルへのリダイレクトです。もちろん、プログラムが ieee_retrospective メッセージ以外の出力を stderr に送信する場合は、この方法を使用してはいけません。

3 番目の方法は、たとえば次のように、プログラム内にダミーの ieee_retrospective 関数を含める方法です。

subroutine ieee_retrospective
return
end

3.4.5 nonstandard_arithmetic(3m)

IEEE 演算で説明されているように、IEEE 演算ではアンダーフローした結果を、段階的 アンダーフローを使用して処理します。SPARC ベースの一部のシステムでは、段階的アンダーフローは多くの場合、演算のソフトウェアエミュレーションを部分的に使用して実装されます。 多くの計算がアンダーフローすると、これによってパフォーマンスが低下する場合があります。

特定のプログラムがこれに該当するかどうかについての何らかの情報を取得するには、ieee_retrospective または ieee_flags を使用してアンダーフロー例外が発生したかどうかを判定し、さらにプログラムによって使用されているシステム時間数をチェックできます。プログラムがオペレーティングシステムで異常に多い時間を費やし、アンダーフロー例外を発生させている場合は、段階的アンダーフローが原因である可能性があります。この場合は、IEEE 以外の演算を使用すると、プログラムの実行が速くなる可能性があります。

関数 nonstandard_arithmetic は、IEEE 以外の演算モードをサポートしているプロセッサ上で、これらの演算モードを有効にします。SPARC システムでは、この関数は、浮動小数点ステータスレジスタ内の NS (非標準の演算) ビットを設定します。SSE 命令をサポートしている x86 システムでは、この関数は、MXCSR レジスタ内の FTZ (0 へのフラッシュ) ビットを設定します。また、DAZ (非正規数が 0) ビットをサポートしているプロセッサ上の MXCSR レジスタ内のこのビットも設定します。非標準モードの影響はプロセッサによって異なり、通常は堅牢なソフトウェアの誤動作を引き起こす場合もあることに注意してください。非標準モードは、通常の使用にはお勧めできません。

関数 standard_arithmetic は、デフォルトの IEEE 演算を使用するようにハードウェアをリセットします。どちらの関数も、デフォルトの IEEE 754 の演算方法のみを提供するプロセッサには影響を与えません。このようなプロセッサの 1 つに SPARC T4 があります。