XL Fortran での丸め操作を理解すれば、予測可能な整合性のある結果を得るのに役立ちます。 また、スピードと正確度との妥協点を定めなければならない場合に、情報を基に決定を下すのにも 役立ちます。
MAF 演算と、中間結果に使用される高い精度のために、XL Fortran プログラムから得られる浮動小数点計算は、 一般に他の処理系の場合よりも正確になります。 XL Fortran デフォルトでの追加の精度やパフォーマンスよりも、まったく同じ結果を得ることのほうが重要な場合は、 他のシステムの浮動小数点結果の再現を参照してください。
プログラムの丸めモードを変更するために、fpsets および fpgets ルーチンを呼び出すことが できます。 これらのルーチンは、インクルード・ファイル /opt/ibmcmp/xlf/9.1/include/fpdt.h および fpdc.h に定義されている fpstat という名前の論理値の配列を使用します。 fpstat 配列エレメントは、浮動小数点の状況レジスターおよび制御レジスターのビットに対応します。
浮動小数点の丸め制御の場合は、配列エレメント fpstat(fprn1) と fpstat(fprn2) が
以下の表に記載されているとおりに設定されます。
表 15. fpsets および fpgets で使用する丸めモード・ビット
fpstat(fprn1) | fpstat(fprn2) | 丸めモードを使用可能にした場合 |
---|---|---|
.true. | .true. | - 無限大方向への丸め |
.true. | .false. | + 無限大方向への丸め |
.false. | .true. | ゼロ方向への丸め |
.false. | .false. | 最も近い値への丸め |
たとえば、次のようになります。
program fptest include 'fpdc.h' call fpgets( fpstat ) ! Get current register values. if ( (fpstat(fprn1) .eqv. .false.) .and. + (fpstat(fprn2) .eqv. .false.)) then print *, 'Before test: Rounding mode is towards nearest' print *, ' 2.0 / 3.0 = ', 2.0 / 3.0 print *, ' -2.0 / 3.0 = ', -2.0 / 3.0 end if call fpgets( fpstat ) ! Get current register values. fpstat(fprn1) = .TRUE. ! These 2 lines mean round towards fpstat(fprn2) = .FALSE. ! +infinity. call fpsets( fpstat ) r = 2.0 / 3.0 print *, 'Round towards +infinity: 2.0 / 3.0= ', r call fpgets( fpstat ) ! Get current register values. fpstat(fprn1) = .TRUE. ! These 2 lines mean round towards fpstat(fprn2) = .TRUE. ! -infinity. call fpsets( fpstat ) r = -2.0 / 3.0 print *, 'Round towards -infinity: -2.0 / 3.0= ', r end ! This block data program unit initializes the fpstat array, and so on. block data include 'fpdc.h' include 'fpdt.h' end
XL Fortran は、 浮動小数点状況とプロセッサーの制御レジスターを直接制御するためのいくつかのプロシージャーを提供しています。 これらのプロシージャーは、浮動小数点状況と制御レジスター (fpscr) を直接操作する インライン・マシン・インストラクションにマップされるため、fpsets および fpgets サブルーチンより効率的です。
XL Fortran は、xlf_fp_util モジュールで get_round_mode() および set_round_mode() プロシージャーを提供します。 これらのプロシージャーはそれぞれ、現行の浮動小数点丸めモードの戻しと設定を行います。
たとえば、次のようになります。
program fptest use, intrinsic :: xlf_fp_util integer(fpscr_kind) old_fpscr if ( get_round_mode() == fp_rnd_rn ) then print *, 'Before test: Rounding mode is towards nearest' print *, ' 2.0 / 3.0 = ', 2.0 / 3.0 print *, ' -2.0 / 3.0 = ', -2.0 / 3.0 end if old_fpscr = set_round_mode( fp_rnd_rp ) r = 2.0 / 3.0 print *, 'Round towards +infinity: 2.0 / 3.0 = ', r old_fpscr = set_round_mode( fp_rnd_rm ) r = -2.0 / 3.0 print *, 'Round towards -infinity: -2.0 / 3.0 = ', r end
XL Fortran は、ieee_arithmetic モジュールで ieee_get_rounding_mode() および ieee_set_rounding_mode() プロシージャーを提供します。 これらの移植可能プロシージャーはそれぞれ、現行の浮動小数点丸めモードの検索と設定を行います。
たとえば、次のようになります。
program fptest use, intrinsic :: ieee_arithmetic type(ieee_round_type) current_mode call ieee_get_rounding_mode( current_mode ) if ( current_mode == ieee_nearest ) then print *, 'Before test: Rounding mode is towards nearest' print *, ' 2.0 / 3.0 = ', 2.0 / 3.0 print *, ' -2.0 / 3.0 = ', -2.0 / 3.0 end if call ieee_set_rounding_mode( ieee_up ) r = 2.0 / 3.0 print *, 'Round towards +infinity: 2.0 / 3.0 = ', r call ieee_set_rounding_mode( ieee_down ) r = -2.0 / 3.0 print *, 'Round towards -infinity: -2.0 / 3.0 = ', r end
注:
丸め誤差や、計算結果におけるその他の予期しないわずかな誤差を処理するいくつかの方法があります。 以下の方法のうちの 1 つまたは複数の方法を考慮してみる必要があるでしょう。
丸め操作 (特にループの場合) によってコードのパフォーマンスは低下するので、計算の精度に対してよくない 影響を与えることがあります。 倍精度計算の一時結果を保管するときは、単精度変数ではなく倍精度を使うようにし、計算の最終結果が 得られるまで丸め操作を遅らせるよう配慮してください。
コンパイラーは、可能なら、コンパイル中に浮動小数点の式を評価します。 したがって、その結果作成されたプログラムは、実行時の不必要な計算で実行スピードが遅くなることがありません。 しかし、コンパイラーの評価による結果は、実行時の計算結果と正確に一致しない場合があります。 これらの計算を実行時まで遅らせるには、-qfloat オプションの nofold サブオプションを指定してください。
それでも結果は同じにならない場合があります。 たとえば、DATA および PARAMETER ステートメント内の計算は、やはりコンパイル時に実行されるからです。
fold/nofold が原因で結果に最も大きな差が出るのは、拡張精度計算を実行したり、 -O オプションでコンパイルされたりする (またはこの両方) プログラムの場合です。
デフォルトで設定されている丸めモードを、最も近い値への丸めモードから変更することができます。 (例を参照してください。) これを行う場合は、プログラムのすべての 丸め操作で同じモードを使用するように 注意しなければなりません。
無限大への丸めモードを一貫して使用した場合は、たとえば次のコマンドを使用して、 丸めモードの選択の例のようなプログラムをコンパイルできます。
xlf95 -qieee=plus -qfloat=rrm changes_rounding_mode.f