インテル® C++ コンパイラー 19.0 デベロッパー・ガイドおよびリファレンス
正規化されていない浮動小数点値とは、正規化で表現するには小さすぎる値です。つまり、仮数は左揃えにできません。デノーマル値を処理するには、ハードウェアまたはオペレーティング・システムの介入が必要です。そのため、結果がデノーマル値になる浮動小数点演算はパフォーマンスに影響することがあります。
デノーマル数を処理し、アプリケーションのパフォーマンスを高める方法はいくつかあります。
値を正規化された数値範囲に変換する
より大きな範囲を持つ高い精度のデータ型を使用する
デノーマル数をゼロにフラッシュする
例えば、大きなスカラー数を掛けて正規数に変換し、正規空間で残りの演算を行った後で、デノーマル範囲に戻す方法があります。小さなデノーマル値がプログラム設計に必要な場合はこの方法を検討してください。
より大きな範囲を持つ高い精度のデータ型を使用する方法もあります。例えば、float として宣言された変数を double として宣言するように変換します。ただし、この変更を加えると、プログラムの遅延を引き起こす可能性があることに注意してください。必要な容量は増え、データのロードと保存により時間がかかります。また、インテル® ストリーミング SIMD 拡張命令 (インテル® SSE) およびインテル® アドバンスト・ベクトル・エクステンション (インテル® AVX) 命令のスループットが悪くなることもあります。
変数の型宣言を変更すると、それがジェネリック型でない限り、関連するライブラリー呼び出しも変えなければならないことがあります (例: cos() の代わりに cosf() など)。また、パフォーマンスを上げる別の方法として、-fp-model [double|extended] オプションを使用して中間値の精度を上げる方法があります。しかし、この方法はすべてのデノーマル例外を排除するとは限りません。使用するアプリケーションのパフォーマンスを試してみてください。デノーマル数を排除することにより得られるパフォーマンス・ゲインが、大きな動的範囲を持つ高い精度のデータ型の使用で発生するオーバーヘッドよりも大きいことを確認する必要があります。
多くの場合、デノーマル数はプログラム結果に大きな影響を与えることなく、ゼロとして安全に扱われます。対象とするアーキテクチャーによって、FTZ (Flush-to-Zero) オプションを使用してください。
これらのアーキテクチャーは、インテル® ストリーミング SIMD 拡張命令 (インテル® SSE) の FTZ (flush-to-zero) および DAZ (denormals-are-zero) 機能を利用できます。
インテル® C++ コンパイラーは O0 以上の最適化レベルにおいて、FTZ および DAZ を有効にするコードをデフォルトでメインルーチンに挿入します。O0 で FTZ および DAZ を有効にするには、main() PROGRAM を含むソースファイルを、[Q]ftz オプションを使用してコンパイルします。[Q]ftz オプションが、-mia32 (Linux* および macOS*) または /arch:IA32 (Windows* オプションとともに IA-32 ベースのシステムで使用されると、コンパイラーは、ランタイム・プロセッサー・チェックに基づいて条件付きで FTZ/DAZ をセットするコードを挿入します。
FTZ を使用した後、正規化されていない値をゼロとして解釈した場合でも、プログラムが正しい結果を出力していることを確認してください。
『Intel® 64 and IA-32 Architectures Software Developer's Manual, Volume 1: Basic Architecture』 (英語)