| 数値計算ガイド |
第 3 章
数学ライブラリ
この章では、Solaris オペレーティング環境と Sun WorkShop Compiler で提供されている数学ライブラリ
libm.a、libm.so、libsunmath.aを含む数学関数の実装について説明します。この章では、各ライブラリの内容を示すとともに、Sun WorkShop Compiler に含まれる数学ライブラリがサポートする機能の一部 (IEEE をサポートする関数、乱数発生機構、IEEE と非 IEEE 形式間でデータを変換する関数など) について説明します。
libmとlibsunmathライブラリの内容は、intro(3M) のマニュアルページにも挙げられています。数学ライブラリ
libm数学ライブラリには、Solaris オペレーティングシステムが準拠している標準に必要な関数が含まれています。このライブラリは、静的ライブラリlibm.aと共有ライブラリlibm.soの 2 つの形式で Solaris に含まれています。標準インストールをした場合の
libmのデフォルトディレクトリは、次のとおりです。
/opt/SUNWspro/<release>/lib/libm.a/opt/SUNWspro/lib/libm.so/usr/lib/libm.a/usr/lib/libm.so
/usr/include/floatingpoint.h/usr/include/math.h/usr/include/sys/ieeefp.h表 3-1 は、ライブラリの関数の一覧です。
関数
gamma_rとlgamma_rは、gammaとlgammaの再入可能バージョンを意味するので注意してください。上記で述べているように、標準の数学ライブラリは 2 か所にインストールできます。
/usr/libに置かれるライブラリは、Solaris オペレーティング環境にバンドルされており、すべてのシステムにインストールされます。一方、/opt/SUNWsproに置かれるライブラリは、Sun WorkShop Compiler に付属しており、コンパイラインストールにアクセスできるシステム上でのみ利用できます。この 2 セットのライブラリは同じインタフェースを使用したまったく同じ関数を提供しますが、わずかな違いがあります。まず、コンパイラに付属した標準の数学ライブラリ内の関数は、Solaris オペレーティング環境にバンドルされたライブラリ内の関数よりも高速な場合があります。また、これらのライブラリの正確度は同等ですが、一定の引数について特定の関数が配布する結果は最下位ビットが異なる場合があります。ほとんどのプログラムはこれらのライブラリ間の数値の違いに特に影響は受けませんが、共有libm.soにリンクされたプログラムをコンパイラに付属のlibm.soを使用したシステムで実行した場合と、デフォルトの Solarislibm.soだけを使用したシステムで実行した場合では、この違いのためにわずかな変化が出ます。また、プログラムを実行する Solaris リリースによっても差が出ることがあります。プログラムが多様な結果を出すのを防ぐ方法はいくつかあります。これは、使用する数学ライブラリによって異なります。
- プログラムを実行するすべてのシステムで希望する
libm.soバージョンが使用できる状態であり、そのlibm.soバージョン が置かれたディレクトリが、プログラムのコンパイル時に-Rオプションで指定されたRPATHか、あるいはプログラムの実行時に有効なLD_LIBRARY_PATHまたはLD_RUN_PATHに含まれていることを確かめます。このディレクトリは、libm.soを含むほかのディレクトリよりも先に現れる必要があります。- ライブラリのフルパス名に環境変数
LD_PRELOADをセットし、コンパイラまたは Solaris に付属の特定のlibm.soバージョンをプリロードします。- 静的アーカイブ
libm.aとリンクします。動的リンクと静的リンク、およびプログラムの実行時に読み込む共有オブジェクトを決定するオプションと環境変数の詳細は、
ld(1) とコンパイラのマニュアルページを参照してください。付加価値数学ライブラリ
Sun 数学ライブラリ
libsunmathライブラリは、サンの言語製品と共に提供されるライブラリの一部です。libsunmathライブラリには、サンの旧バージョンのlibmに組み込まれていた関数が格納されています。
libsunmathがインストールされるデフォルトのディレクトリ
/opt/SUNWspro/<release>/lib/libsunmath.a/opt/SUNWspro/lib/libsunmath.so
libsunmathのヘッダーファイルがインストールされるデフォルトのディレクトリ
/opt/SUNWspro/<release>/include/cc/sunmath.h/opt/SUNWspro/<release>/include/f77/f77_floatingpoint.h次の表 3-2 は、
libsunmathに含まれる関数を示しています。この表では、数学関数ごとに、C プログラムから呼び出される場合の、関数の倍精度名だけを示しています。
表 3-2 libsunmathの内容表 3-1 からの関数 matherrを除く単精度および拡張 / 4 倍精度の関数基本超越正関数 exp2、exp10、log2、sincos三角関数 (度数) asind、acosd、atand、atan2d、
sind、cosd, sincosd、tandπ で基準化 (スケール)
した三角関数asinpi、acospi、atanpi、atan2pi、
sinpi、cospi、sincospi、tanpi倍精度 π 引数還元のある三角関数 asinp、acosp、atanp、
sinp、cosp、sincosp、tanp財務関数 annuity、compound整数丸め関数 aint、anint、irint、nintIEEE 規格で勧告済みの
関数signbitIEEE 分類の関数 fp_class、isinf、isnormal、issubnormal、iszero有用な IEEE 値を与える
関数min_subnormal、 max_subnormal、
min_normal、 max_normal、
infinity、signaling_nan、quiet_nan加法的乱数の生成 i_addran_、i_addrans_、i_init_addrans_、i_get_addrans_、i_set_addrans_、
r_addran_、r_addrans_、r_init_addrans_、r_get_addrans_、r_set_addrans_、
d_addran_、d_addrans_、d_init_addrans_、d_get_addrans_、d_set_addrans_、
u_addrans_線形合同乱数の生成 i_lcran_、i_lcrans_、i_init_lcrans_、i_get_lcrans_、i_set_lcrans_、
r_lcran_、r_lcrans_、d_lcran_、d_lcrans_、
u_lcrans_桁上げ乗算乱数の生成 i_mwcran_、i_mwcrans_、i_init_mwcrans_、i_get_mwcrans_、i_set_mwcrans、
i_lmwcran_、i_lmwcrans_、i_llmwcran_、i_llmwcrans_、
u_mwcran_、u_mwcrans_、u_lmwcran_、u_lmwcrans、u_llmwcran_、u_llmwcrans_、
r_mwcran_、r_mwcrans_、d_mwcran_、d_mwcrans_,smwcran_乱数シャフル i_shufrans_、r_shufrans_、d_shufrans_、u_shufrans_データ変換 convert_external制御丸めモード、および浮動小数点例外フラグ ieee_flags浮動小数点トラップ処理 ieee_handler、sigfpe状態表示 ieee_retrospective標準外演算の
有効化 / 無効化standard_arithmetic、nonstandard_arithmetic
最適化ライブラリ
一部の
libmルーチン中の最適化バージョンは、libmoptライブラリによって提供されます。一部のlibc中のサポートルーチンは、libcoptライブラリによって提供されます。また、SPARC では、一部のlibcサポートルーチンの代替はlibcxによって提供されます。標準インストールをした場合の
libmopt、libcopt、libcxのデフォルトディレクトリは以下のとおりです。
/opt/SUNWspro/<release>/lib/<arch>/libmopt.a/opt/SUNWspro/<release>/lib/<arch>/libcopt.a/opt/SUNWspro/<release>/lib/<arch>/libcx.a(SPARC のみ)/opt/SUNWspro/<release>/lib/<arch>/libcx.so.1(SPARC のみ)(
<arch>はアーキテクチャ固有のライブラリディレクトリを示す。SPARC では、v7、v8、v8a、v8plus、v8plusa、v8plusb、v9、v9a、v9bなど。x86 プラットフォームでは、提供されるディレクトリはf80387のみ。)
-xarchの詳細は、『Fortran ユーザーズガイド』 、『C ユーザーズガイド』または『C++ ユーザーズガイド』を参照してください。
libcoptに含まれるルーチンは、ユーザーが直接呼び出すことはできません。その代わり、libc内にサポートルーチンを置き換えて、コンパイラが使用できるようにします。
libmoptに含まれるルーチンは、libm内の対応するルーチンに置き換えられます。libmoptバージョンの処理速度は、一般的に著しく速くなります。これは、libmバージョンは、ANSI/POSIX、SVID、X/Open、または IEEE 形式の例外のケースを処理するために構成されますが、libmoptルーチンは IEEE 形式の例外のケースの処理のみをサポートするためです (付録 E を参照してください)。
ccを使用してlibmoptとlibcoptの両方とリンクするには、コマンド行で-lmoptと-lcoptオプションを指定します (-lmの直前に-lmoptを置き、-lcoptを最後に置くともっともよい結果となる)。ほかのコンパイラを使用してこの 2 つのライブラリとリンクする場合は、コマンド行の任意の位置に-xlibmoptフラグを指定します。SPARC では、ライブラリ
libcxに 128 ビット 4 倍精度浮動小数点算術演算サポートルーチンよりも速いバージョンを含みます。これらのルーチンはユーザーが直接呼び出すことはできず、コンパイラによって呼び出されます。-nocxオプションが指定されていない場合、FORTRAN 77 コンパイラでは自動的にlibcxと共にリンクが行われますが、C コンパイラでは行われません。C プログラムでlibcxを使用するには、-lcxとともにリンクを行なってください。
libcxの共有バージョン (libcx.so.1) も提供されます。共有バージョンを実行時にあらかじめロードするには、環境変数LD_PRELOADをlibcx.so.1ファイルのフルパス名に指定してください。パフォーマンスを最大にするには、使用しているシステムのアーキテクチャに該当するlibcx.so.1を使用します。たとえば UltraSPARC システムでは、ライブラリがデフォルトの位置にインストールされている場合、LD_PRELOADを次のように設定します。
setenv LD_PRELOAD /opt/SUNWspro/lib/v8plus/libcx.so.1
LD_PRELOAD=/opt/SUNWspro/lib/v8plus/libcx.so.1
export LD_PRELOADベクトル数学ライブラリ (SPARC のみ)
SPARC プラットフォームでは、
libmvecライブラリの提供するルーチンは、引数の全部のベクトルに対して共通数学関数を評価します。標準インストールを行なった場合の
libmvecのデフォルトディレクトリは次のとおりです。
/opt/SUNWspro/<release>/lib/<arch>/libmvec.a/opt/SUNWspro/<release>/lib/<arch>/libmvec_mt.a表 3-3 は、
libmvec中の関数を一覧しています。
libmvec_mt.aはマルチプロセッサの並列化にもとづいて、ベクトル関数の並列化バージョンを提供します。libmvec_mt.aを使用するには、-xparallelと共にリンクしなければなりません。詳細は、
libmvec(3m) およびclibmvec(3m) のマニュアルページを参照してください。
libm9X数学ライブラリ
libm9x数学ライブラリには、C99 で規定されている数学および浮動小数点に関した関数の一部が含まれています。Sun WorkShop 6 Compiler リリースでは、改良された浮動小数点例外処理をサポートするために、<fenv.h>
(Floating-Point Environment、浮動小数点環境) 関数および各種の拡張プログラムがこのライブラリに含まれています。
libm9xの標準インストールの場合、デフォルトディレクトリは次のとおりです。
/opt/SUNWspro/lib/libm9x.so
libm9xのヘッダーファイルの標準インストールの場合、デフォルトディレクトリは次のとおりです。
/opt/SUNWspro/<release>/include/cc/fenv.h/opt/SUNWspro/<release>/include/cc/fenv96.h次の表 3-4 は、
libm9xに含まれる関数を示しています (精度制御関数fegetprecとfesetprecは、x86 プラットフォームのみに含まれています)。
libm9xは、共有ライブラリとしてのみ提供されています。ccコンパイラは、リンク時に共有ライブラリのインストールディレクトリ内でライブラリを自動的に検索することはありません。そのため、ccを使用してlibm9xとリンクする場合は、静的リンカーと実行時リンカーの両方を有効にして、ライブラリを検出する必要があります。libm9xを検出するために静的リンカーを有効にするには、次の 3 つの方法のいずれかを使用します。
- コマンド行で、
-lm9xの前に-L/opt/SUNWspro/libを指定する。- コマンド行で、フルパス名
/opt/SUNWspro/lib/libm9x.soを指定する。- 環境変数
LD_LIBRARY_PATHが指定するディレクトリリストに/opt/SUNWspro/libを追加する。
libm9xを検出するために実行時リンカーを有効にするには、次の 3 つの方法のいずれかを使用します。
- リンク時に
-R/opt/SUNWspro/libを指定する。- リンク時に環境変数
LD_RUN_PATHが指定するディレクトリリストに/opt/SUNWspro/libを追加する。- 実行時に環境変数
LD_LIBRARY_PATHが指定するディレクトリリストに/opt/SUNWspro/libを追加する。
注 - 環境変数LD_LIBRARY_PATHに/opt/SUNWspro/libを追加すると、Sun Performance Library にリンクされているプログラムは、プログラムが動作するシステムにもっとも適したライブラリ以外のライブラリバージョンを使用してしまいます。ccとリンクされたプログラム内でlibm9xと Sun Performance Library の両方を使用する場合は、LD_LIBRARY_PATHに/opt/SUNWspro/libを追加せず、コマンド行で-lm9xの前に-xlic_lib=sunperfを指定するだけにしてください。
ほかの Sun WorkShop Compiler はすべて、自動的に共有ライブラリのインストールディレクトリを検索します。これらのコンパイラのどれかを使用して
libm9xとリンクするには、コマンド行で-lm9xと指定してください。libm9xは主に C および C++ プログラムでの使用を想定したものですが、FORTRAN プログラムでも使用できます。例は、付録 A を参照してください。単精度、倍精度、4 倍精度
多くの数値関数は単精度、倍精度、および 4 倍精度で使用できます。他言語から異なった精度のバージョンを呼び出す例を、表 3-5 に示します。
C では、単精度関数の名前は倍精度名に
fを付加し、4 倍精度関数の名前は倍精度名にlを付加することで作成されます。FORTRAN 呼び出し規約は異なっているので、libsunmathは単精度関数、倍精度関数、および 4 倍精度関数用にそれぞれr_... 、d_... 、およびq_... バージョンを提供しています。FORTRAN 組み込み関数は、3 種類の精度のすべてについて総称で呼び出すことができます。すべての関数が
q_... バージョンを持っているわけではありません。libmとlibsunmath関数の名前と定義については、<math.h>と<sunmath.h>を参照してください。FORTRAN プログラムの中で
r_... 関数をreal、d_... 関数を倍精度、q_... 関数をreal*16として宣言することを忘れないでください。そうしないと、結果として型が不整合になることがあります。
注 - x86 バージョンの FORTRAN では単精度と倍精度だけがサポートされ、REAL*16はサポートされません。ただし、x86 バージョンの C では 4 倍精度がサポートされます。
IEEE サポート関数
この節では、IEEE 推奨関数、有益な値を与える関数、
ieee_flags、ieee_retrospective、およびstandard_arithmeticとnonstandard_arithmeticについて説明します。関数ieee_handlerおよびieee_flagsついての詳細は、第 4 章を参照してください。
ieee_functions(3m) とieee_sun(3m)
ieee_functions(3m) とieee_sun(3m) によって記述される関数は、IEEE 規格で要求される機能または IEEE 規格の付録で推奨される機能を備えています。これらはビットマスク演算として効率的に実装されています。
remainder(x,y)は、IEEE 規格 754-1985 で規定された演算です。remainder(x,y)とfmod(x,y)の相違は、fmod(x,y)が常にxと一致する符号を持つ結果を返すのに対し、remainder(x,y)が返す結果の符号はxまたはyの符号のどちらとも一致しないことがあるという点です。両関数とも明確な結果を返し、不明確な例外は発生しません。
表 3-9 FORTRAN からの ieee_sunの呼び出しsignbit(x)i=ir_signbit(x)i=id_signbit(x)i=iq_signbit(x)
注 - ユーザーはd_<関数>およびq_<関数>を使用する FORTRAN プログラムの中でd_<関数>を倍精度として宣言し、q_<関数>をREAL*16として宣言する必要があります。
ieee_values(3m)
ieee_values(3m) のマニュアルページに記述されている特殊関数によって、無限大、NaN、および最大/最小浮動小数点数のような IEEE 値が得られます。ieee_values(3m) 関数によって記述される 10 進値と 16 進の IEEE 表現を、
表 3-10、表 3-11、表 3-12、表 3-13 に示します。
ieee_flags(3m)
ieee_flags(3m) は、以下の機能に対する SUN インタフェースを提供しています。
ieee_flags(3m) 呼び出しの構文は次の通りです。
i = ieee_flags (action, mode, in, out);パラメータに対して設定できる値の ASCII 文字列を表 3-14 に示します。
パラメータについての詳細は、
ieee_flags(3m) のマニュアルページを参照してください。以降に、
ieee_flagsを使用すると変更可能な算術演算機能を簡単に説明します。ieee_flagsおよび IEEE 例外フラグについての詳細は、第 4 章を参照してください。mode が
directionの時、指定された動作は現在の丸め方向に適用されます。丸め方向は、表現可能な最も近い数に丸める、ゼロ方向に丸める、+· 方向に丸める、-· 方向に丸めるのいずれかに設定できます。IEEE のデフォルトの丸め方向は、表現可能な最も近い数に丸めるよう設定されています。算術演算結果が 隣接する2 つの表現可能な数の間にあるとき、算術結果に近い値が結果となります。算術演算結果が表現可能なもっとも近い 2 つの数のちょうど中間にある場合には、最下位ビットがゼロである値が結果となります。このことを強調するように、表現可能なもっとも近い数への丸めは、もっとも近い偶数値への丸めとも呼ばれます。ゼロ方向に丸める方法は、IEEE 規格以前に多くのコンピュータが採用していた方法です。これは、数学的には演算結果の切り捨てを意味します。たとえば、2/3 を 6 桁の 10 進数に丸める場合、表現可能な最も近い数に丸めると .666667 になりますが、ゼロ方向に丸めると .666666 になります。
丸め方向の確認、クリアーまたは設定に
ieee_flagsを使用するときに、4 つの入力パラメータが取り得る値を、表 3-15 に示します。
表 3-15 ieee_flagsによる丸め方向の入力値action get、set、clear、clearallin nearest、tozero、negative、positiveout nearest、tozero、negative、positive
mode が
precisionの時、指定した動作は現在の丸め精度に適用されます。x86 プラットフォームでは、丸め精度は、単精度、倍精度、拡張精度に設定できます。デフォルトの丸め精度は拡張精度です。このモードでは、浮動小数点レジスタに渡される算術演算の結果は、完全な 64 ビット精度の拡張倍精度レジスタの形式に丸められます。丸め精度が単精度または倍精度の場合は、浮動小数点レジスタに渡される算術演算の結果は、それぞれ上位の 24 ビットまたは 53 ビットに丸められます。拡張丸め精度を使用してもほとんどのプログラムでは少なくとも正確な結果が得られますが、IEEE 算術演算の論理に厳密に準拠している必要があるプログラムの中には、拡張丸め精度モードで正常に動作しないものがあります。このようなプログラムは単精度または倍精度に設定された丸め精度で実行する必要があります。SPARC アーキテクチャを使用しているシステムでは、丸め精度は設定できません。丸め精度に関連する
ieee_flagsの呼び出しは、現在の実装では演算結果に影響を与えません。mode が
exceptionの時、指定された動作は現在の IEEE 例外フラグに適用されます。ieee_flagsを使用して IEEE 例外フラグを調べ制御する方法についての詳細は、第 4 章を参照してください。
ieee_retrospective(3m)
libsunmath関数ieee_retrospectiveは、不要な例外および非標準 IEEE モードに関する情報をstderrに出力します。この関数は以下の事項を判断します。これらの情報はハードウェア浮動小数点状態レジスタに格納されます。
ieee_retrospectiveは、例外フラグ、および対応するトラップが有効になっている例外についての情報を出力します。これら 2 つの異なった情報を混同しないように気を付けてください。例外フラグが発生している場合、それはプログラム実行中のある時点で発生して無視された例外です。例外に対応するトラップが有効であれば、例外は実際には発生していないことがあります。例外が発生している場合は、SIGFPE シグナルが送信されます。ieee_retrospectiveメッセージは、調査する必要のある例外についてユーザーに警告する (例外フラグが発生している場合) か、または例外がシグナルハンドラによって処理されていることをユーザーに知らせます (例外がトラップされた場合)。例外がシグナルハンドラをトラップすると、その例外はもう発生しません。例外、シグナル、トラップ、通知された例外の原因調査方法については、第 4 章を参照してください。
ieee_retrospectiveはいつでも呼び出すことができますが、通常出口の前で呼び出します。FORTRAN 77 でコンパイルされたプログラムでは、デフォルトでieee_retrospectiveを出口で呼び出します。
- C および C++
ieee_retrospective_(fp);- FORTRAN
call ieee_retrospective()C の関数の場合、引数 fp には出力ファイルを指定します。FORTRAN 関数の場合、常に標準エラー出力に出力されます。
この例は、6 種類ある
ieee_retrospective警告メッセージの中の 4 種類を示しています。
警告メッセージは、トラップが有効になっているか、例外が発生した場合にのみ表示されます。
FORTRAN プログラムからの
ieee_retrospectiveメッセージを抑制するには 3 つの方法があります。1 つめの方法では、処理されていない例外をすべてクリアーし、トラップを無効にし、プログラムが終了する前の、近似値に丸める、拡張精度、標準モードを復元します。これを行うには、次のようにieee_flags、ieee_handlerおよびstandard_arithmeticを呼び出します。
character*8 outi = ieee_flags('clearall', '', '', out)call ieee_handler('clear', 'all', 0)call standard_arithmetic()
注 - 原因を調査せずに、処理されていない例外をクリアーすることはお勧めしません。
ieee_retrospectiveメッセージが表示されないようにするもう 1 つの方法は、標準エラー出力 (stderr) をファイルにリダイレクトする方法です。プログラムがieee_retrospective以外のメッセージをstderrに出力する場合は、この方法を使用しないでください。3 つめの方法は、次のようにダミーの
ieee_retrospective関数をプログラムに組み込む方法です。
subroutine ieee_retrospectivereturnend
nonstandard_arithmetic(3m)第 2 章で説明したように、IEEE 演算では、段階的アンダーフローを使用して、アンダーフロー例外を処理します。一部の SPARC システム上では、演算のソフトウェアエミュレーションを通じて段階的アンダーフローが実装される場合があります。そのような場合に数多くの計算でアンダーフローが発生すると、性能を低下させる原因となることがあります。
特定のアプリケーションで上記のような状況が発生しているかどうかを調べる場合は、
ieee_retrospectiveまたはieee_flagsを使用して、アンダーフロー例外の発生有無を確認し、プログラムで使用されているシステム時間をチェックします。プログラムが多大な時間をシステム呼び出しに費やし、アンダーフロー例外が発生している場合は、段階的アンダーフローが性能低下の原因と考えられます。このような場合には、IEEE 以外の演算機能を使用すると、プログラムの実行速度が上がります。
nonstandard_arithmetic関数を呼び出した場合、ゼロへのフラッシュが高速に行われるようなハードウェアモードの SPARC 実装上では、アンダーフローした結果がゼロにフラッシュされます。ただし、段階的アンダーフローの利点が失われるため、高速になる代わりに正確性が低下します。
standard_arithmetic関数を呼び出すと、ハードウェアがリセットされ、デフォルトの IEEE 演算機能が復元されます。これら 2 つの関数は、IEEE 754 形式のデフォルト演算機能しか利用できない実装 (SuperSPARCTMなど) では効果がありません。C99 浮動小数点環境関数
この節では、C99 で規定されている
<fenv.h>浮動小数点環境関数について説明します。Sun WorkShop 6 Compiler リリースでは、libm9x.soライブラリにこれらの関数があります。これらの関数にはieee_flags関数と同じ機能が多数ありますが、より自然な C インタフェースが使用されており、C99 で定義されているため、将来は移植性がさらに向上する可能性があります。
注 - 一貫した動作を保つため、libm9x.soに含まれる C99 浮動小数点環境関数と例外処理の拡張機能、およびlibsunmath内のieee_flagsとieee_handler関数の両方を同じプログラム内で使用することは避けてください。
例外フラグ関数
fenv.hファイルは、5 つの IEEE 浮動小数点例外フラグ (FE_INEXACT、FE_UNDERFLOW、FE_OVERFLOW、FE_DIVBYZERO、およびFE_INVALID) のそれぞれに対してマクロを定義しています。また、5 つのフラグマクロすべてのビット単位の論理和となるように、マクロFE_ALL_EXCEPTを定義します。以下の説明では、excepts パラメータは 5 つのフラグマクロのいずれかのビット単位の論理和であるか、値FE_ALL_EXCEPTです。fegetexceptflag関数とfesetexceptflag関数の場合は、flagp パラメータが型fexcept_t(この型はfenv.hで定義されている) のオブジェクトを指すポインタでなければなりません。
feclearexcept関数は、指定されたフラグをクリアーします。fetestexcept関数は、設定されている excepts 引数が指定するフラグのサブセットに対応するマクロ値のビット単位の論理和を返します。たとえば、現在設定されているフラグだけが不正確な場合、アンダーフローが発生し、ゼロ除算が行われ、次の記述がiをFE_DIVBYZEROにセットします。
i = fetestexcept(FE_INVALID | FE_DIVBYZRO);
feraiseexcept関数は、指定された例外のトラップのいずれかが有効であれば、トラップを発生させます (例外トラップの詳細は、第 4 章を参照)。有効なトラップがない場合は、対応するフラグをセットするだけです。
fegetexceptflag関数とfesetexceptflag関数は、特定のフラグの状態を一時的に保存しておき、あとでその状態を復元するのに便利です。fesetexceptflag関数は、トラップを発生させません。この関数は、指定されたフラグの値を復元するだけです。丸め制御
fenv.hファイルは、IEEE の 4 つの丸め方向モードであるFE_TONEAREST、FE_UPWARD(正の無限大の方向)、FE_DOWNWARD(負の無限大の方向)、およびFE_TOZEROのそれぞれについてマクロを定義しています。C99 は、丸め方向モードを制御する 2 つの関数を定義しています。fesetroundは、現在の丸め方向をその引数 (これは上記の 4 つのマクロの 1 つでなければならない) で指定された方向に設定します。fegetroundは、現在の丸め方向に対応するマクロの値を返します。x86 プラットフォームでは、
fenv.hファイルは 3 つの丸め精度モード、FE_FLTPREC(単精度)、FE_DBLPREC(倍精度)、およびFE_LDBLPREC(拡張倍精度) のそれぞれについてマクロを定義しています。これらは C99 には含まれませんが、x86 上のlibm9x.soは、丸め精度モードを制御する 2 つの関数を提供します。fesetprecは、現在の丸め精度をその引数 (これは上記の 3 つのマクロの 1 つでなければならない) で指定された精度に設定します。fegetprecは、現在の丸め精度に対応するマクロの値を返します。環境関数
fenv.hファイルは、例外フラグ、丸め制御モード、例外処理モード、標準外モード (標準外モードは SPARC の場合のみ) など、浮動小数点環境全体を表現するデータ型fenv_tを定義しています。以下の説明では、envp パラメータは型fenv_tのオブジェクトのポインタでなければなりません。C99 は、浮動小数点環境を操作する 4 つの関数を定義しています。
libm9x.soは、マルチスレッド対応のプログラムに便利なその他の関数を提供しています。これらの関数の概要を次の表に示します。
fegetenv関数は、浮動小数点環境を保存します。fesetenv関数は、浮動小数点環境を復元します。fesetenvに対する引数は、fegetenvまたはfeholdexceptの呼び出しによって先に保存されている環境のポインタか、fenv.hで定義されている定数FE_DFL_ENVのどちらかです。FE_DFL_ENVは、すべての例外フラグのクリアー、最近似への丸め (x86 では拡張倍精度への丸めも含む)、連続した例外処理モード (トラップが無効になる)、および無効にされた標準外モード (SPARC の場合) によるデフォルトの環境を表現します。
feholdexcept関数は、現在の環境を保存したあとすべての例外をクリアーし、すべての例外に対して連続した例外処理モードを確立します。feupdateenv関数は、保存されている環境 (fegetenvまたはfeholdexceptの呼び出しによって保存されているもの、または定数FE_DFL_ENV) を復元し、そのあとで以前の環境でフラグがセットされている例外を発生させます。それらの例外のいずれかに対して有効になったトラップが、復元される環境に含まれる場合は、トラップが発生します。それ以外の場合は、フラグがセットされます。次のコード例に示すように、これらの 2 つの関数はあわせて使用し、例外を発生させそうなサブルーチンを呼び出すことができます。
fex_merge_flags関数は、トラップを発生させることなく、保存済みの環境の例外フラグの論理和をとり現在の環境に入れるだけです。この関数をマルチスレッド対応のプログラムで使用すると、子スレッドでの計算で発生したフラグに関する情報を親スレッドに保持できます。fex_merge_flagsの使用方法を示した例は、付録 Aを参照してください。
libmとlibsunmathの実装上の特徴この節では、使用可能な
libmとlibsunmathの実装上の特徴について説明します。アルゴリズム
SPARC システム上の
libmおよびlibsunmath中の基本関数は、テーブル駆動型および多項式有理数の近似値のアルゴリズムによって実装されています。x86 プラットフォーム上のlibmおよびlibsunmath中の基本関数には、x86 命令セット中に提供されている基本関数カーネル命令を使用して実装されているものと、SPARC システムで使用されているのと同じテーブル駆動型および多項式有理数の近似値アルゴリズムによって実装されているものがあります。
libm中の共通の基本演算およびlibsunmath中の単精度基本演算に対する、テーブル駆動型および多項式有理数の近似値のアルゴリズムは、最後の place 内の 1 単位
(ulp = unit-in-the-last-place ) 中だけで正確な結果を算出します。SPARC システムでは、libsunmath中の共通の 4 倍精度基本演算は、1 ulp 中で正確な結果を算出します (expmllおよびloglpl演算を除く)。expmllおよびloglpl演算は、2 ulp 中で正確な結果を算出します (共通の関数には、指数関数、対数関数、累乗関数、ラジアン引数の循環三角関数などがあります。双曲線三角関数や高度な超越関数のようなその他の関数は、正確度が低くなります)。これらのエラー境界は、アルゴリズムを直接分析して調べることができます。BeEF(Berkley Elementary Function) 検査プログラムを使用して、これらのルーチンの正確度を検査することもできます。BeEFは、Z.Alex Liu によって開発され、ucbtestパッケージのnetlibから入手できます (http://www.netlib.org/fp/ucbtest.tgz)。三角関数の引数還元
範囲 [-π/4, π/4] の外側のラジアン引数に対する三角関数は、通常 π/2 の整数倍を引いて、引数を指定された範囲内に還元して計算します。
π はマシンで表現可能な数ではないので、何らかの方法で近似する必要があります。最終的に計算された三角関数の誤差は、引数還元の丸め誤差 (近似 π と丸めによる) と、還元された引数の三角関数計算の誤差で決まります。相当に大きい引数の場合でも、引数還元に起因する誤差は他の誤差より大きくありませんが、これに反して相当に小さい引数の場合は、最終結果の相対誤差は引数還元誤差によって左右されます。
マシンで表現可能な大きい数は、π より大きい範囲で分割されているという理由から、大きな引数の三角関数は本来不正確で、小さい引数はすべて比較的正確であるという誤解が広まっています。
しかし、計算した 三角関数の値が急に大きくなるという固有の境界はなく、不正確な関数値が役に立たないということもありません。引数還元が一様に行われるならば、基本的同一性と関連性が大きい引数に対しても小さい引数と同様に保護されるので、引数還元が π への近似で行われたという事実はほとんど検知できません。
libmとlibsunmath三角関数は、引数還元のため「無限に」正確な π を使用します。値 2/π は 16 進数 916 桁まで計算され、参照用テーブルに格納されて引数還元中に使用されます。関数
sinpi、cospi、およびtanpiのグループ (表 3-2 を参照) は、引数の一定範囲への縮小によって不正確になることを避けるため π で入力引数を基準化 (スケール) します。データ変換ルーチン
libmとlibsunmathには、IEEE 形式とそれ以外の形式間で 2 進浮動小数点データの変換に使用されるデータ変換ルーチンconvert_externalがあります。サポートする形式には、SPARC (IEEE)、IBM PC、VAX、IBM S/370、および Cray が使用する形式が含まれます。
Cray で生成されたデータを関数
convert_externalを使用して、SPARC システムが希望する IEEE 形式に変換する例については、convert_external(3m) のマニュアルページを参照してください。乱数発生機構
32 ビット整数、単精度浮動小数点、および倍精度浮動小数点の各形式で、一様疑似乱数を生成する 3 つの方法を次に示します。
addrans(3m) のマニュアルページに述べられた関数は、テーブル駆動型の加法的乱数ジェネレータのグループに基づいています。lcrans(3m) のマニュアルページに述べられた関数は、線形合同乱数ジェネレータに基づいています。mwcrans(3m) のマニュアルページに述べられた関数は、桁上げ乗算による乱数ジェネレータに基づいています。これらの関数には、64 ビット整数形式の一様疑似乱数を提供するジェネレータも含まれています。また、
shufrans(3m) のマニュアルページに述べられた関数をこれらの任意のジェネレータとあわせて使用すると、疑似乱数の配列を動かし、アプリケーションにより大きなランダム性を与えることができます (64 ビット整数の配列を動かす方法はありません)。各乱数機能には、一度に 1 つ (関数呼び出しごとに 1 つ) の乱数を生成するルーチンと、一度の呼び出しで乱数の配列を生成するルーチンが含まれています。一度に 1 つの乱数を生成する関数は、次の表 3-18 に示す範囲の数値を配布します。
一度の呼び出しで乱数の配列全体を生成する関数を使用すると、生成される数値の範囲を指定できます。付録 Aでは、異なる間隔で一様に分布される乱数の配列を生成する方法を示したいくつかの例が挙げられています。
addransおよびmwcransジェネレータは、lcransジェネレータよりも一般に効率的ですが、これらのジェネレータの理論は精緻ではありません。線形合同アルゴリズムの理論的な特性については、"Communications of the ACM" の 1988 年 10 月号に掲載された S. Park と K. Miller による "Random Number Generators: Good Ones Are Hard To Find" で説明されています。また、加法的乱数ジェネレータについては、Knuth の『The Art of Computer Programming』の第 2 版で説明されています。
|
サン・マイクロシステムズ株式会社 Copyright information. All rights reserved. |
ホーム | 目次 | 前ページへ | 次ページへ | 索引 |