インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
一般に、浮動小数点アプリケーションのプログラミングの目標は、次のカテゴリーに分けられます。
アプリケーションの目標に基づいて、これらの要素のトレードオフを考慮する必要があります。例えば、3D グラフィック・エンジンを開発していれば、パフォーマンスが最も重要な考慮事項であり、再現性と精度は、それに次ぐ考慮事項になるかもしれません。
インテル® C++ コンパイラーは、特定の目標に合わせてアプリケーションをチューニングするコンパイラー・オプションを提供します。オプションには、-fp-model (Linux* および macOS*) または /fp (Windows*) のように浮動小数点固有のものや、[Q]imf-max-error のように高速ですが精度の低いものがあります。コンパイラーは、指定されたコンパイラー・オプションに従って、異なる最適化手法をコードに適用します。プログラミング目標を調整し、適切なコンパイラー・オプションを選択して、各要素間のトレードオフを行ってください。一部のオプションは、呼び出される数学ルーチンの種類に影響します。
libirc、libm、および svml ライブラリーの多くのルーチンは、互換マイクロプロセッサーよりもインテル製マイクロプロセッサーでより高度に最適化されます。
次にコード例を示します。
例 |
---|
float t0, t1, t2; ... t0=t1+t2+4.0f+0.1f; |
精度を優先して、-fp-model extended オプション (Linux* および macOS*) または /fp:extended オプション (Windows*) を指定すると、コンパイラーは次のアセンブリー・コードを生成します。
fld DWORD PTR _t1 fadd DWORD PTR _t2 fadd DWORD PTR _Cnst4.0 fadd DWORD PTR _Cnst0.1 fstp DWORD PTR _t0
このコードは、ターゲット・プラットフォームで可能な最も高い仮数精度を利用するため、最大限の精度を維持します。x87 スタックを管理する場合、パフォーマンスが低下する恐れがあります。また、同等の拡張精度型を持たない他のプラットフォームで結果を再現できないかもしれません。
再現性と移植性を優先して、-fp-model source オプション (Linux* および macOS*) または /fp:source オプション (Windows*) を指定すると、コンパイラーは次のアセンブリー・コードを生成します。
movss xmm0, DWORD PTR _t1 addss xmm0, DWORD PTR _t2 addss xmm0, DWORD PTR _Cnst4.0 addss xmm0, DWORD PTR _Cnst0.1 movss DWORD PTR _t0, xmm0
このコードは、元の順序の計算を維持し、IEEE の単精度型をすべての計算に使用することにより、最大限の移植性をもたらします。ただし、中間式の丸め誤差が拡張精度に比べて多くなるため、最初の例ほどの精度はありません。4.0f + 0.1f. の事前計算を行わないため、パフォーマンスも最大ではありません。
パフォーマンスを優先して、-fp-model fast オプション (Linux* および macOS*) または /fp:fast オプション (Windows*) を指定すると、コンパイラーは次のアセンブリー・コードを生成します。
movss xmm0, DWORD PTR _Cnst4.1 addss xmm0, DWORD PTR _t1 addss xmm0, DWORD PTR _t2 movss DWORD PTR _t0, xmm0
このコードは、インテル® ストリーミング SIMD 拡張命令 (インテル® SSE) 命令を使用し、4.0f + 0.1f. を事前計算することにより、最大限のパフォーマンスをもたらします。ただし、中間式の丸め誤差が多いため、最初の例ほどの精度はありません。また、4.0f + 0.1f を事前計算することで加算の順序を変更するため、2 つ目の例のように結果の再現性はありません。すべてのコンパイラー、すべてのプラットフォーム、すべての最適化レベルで同じように加算の順番が適用されるとは限りません。
多くのアプリケーションでは、このような要件はさらに複雑になるでしょう。
高速ですが精度の低いオプションは、数学関数の精度を制御し、インテル® マス・カーネル・ライブラリー (インテル® MKL) によるパフォーマンス/精度のトレードオフを簡単に利用できるようにします。コマンドライン・インターフェイスで、すべての数学関数または選択した数学関数セットの精度を、high、medium、low よりも細かいレベルで指定できます。
コンパイラーが数学ライブラリーから適切な関数実装を選択する際に関数属性のセットを指定することで、精度を制御します。max-error 属性を使用する例を以下に示します。例えば、次のオプションは、すべての single、double、long double、および quad 精度の関数の相対誤差を 2 ulps (unit in the last place: 最後の桁の単位) に指定します。
-fimf-max-error=2
sin 関数の精度を 12 ビットにする場合は、次のように指定します。
-fimf-accuracy-bits=12:sin
sin 関数の相対誤差を 10 ulps、コンパイルするソースファイルで呼び出される他の数学関数の相対誤差を 4 ulps にする場合は、次のように指定します。
-fimf-max-error=10:sin -fimf-max-error=4
インテル® C++ コンパイラーは max-error 属性のデフォルト値を、/fp オプションと /Qfast-transcendentals オプションによって定義します。/fp:fast モード、または高速で少し精度が低い数学関数が /Qfast-transcendentals- で明示的に指定されると、インテル® C++ コンパイラーは呼び出しに対して max-error=4.0 を設定します。それ以外の場合は、max-error=0.6 を設定します。
インテル® C++ コンパイラーは、コンパイルオプションでコードをチューニングするターゲット CPU が指定され、コードのコンパイルに利用可能な命令セットがチューニングするターゲット CPU で利用可能な命令セットよりも下位の命令使用である場合、libm および svml ライブラリーのルーチン呼び出しを CPU 固有の直接呼び出しに最適化します。
次に例を示します。
2 つ目の例では、_allow_cpu_features()/_may_i_use_cpu_feature() 組込み関数を利用して一部のコード領域で利用可能な命令セットを拡張することで、exp() のインテル® AVX2 固有バージョンへの直接呼び出しが生成される可能性があります。
ディスパッチの最適化は、exp() ルーチンとライブラリーに含まれる CPU 固有の実装を持つその他の数学ルーチンに適用されます。ディスパッチの最適化は、-[f|Q]imf-force-dynamic-target オプションで無効にできます。このオプションは、動的なディスパッチにより改善される数学ルーチンのリストを指定します。(構文例は、インテル® C++ コンパイラーのドキュメントを参照してください。)