回答:
おっしゃったように、厳密なIEEE準拠を維持しない最適化が可能です。
例はこれです:
x = x*x*x*x*x*x*x*x;
に
x *= x;
x *= x;
x *= x;
浮動小数点演算は結合的ではないため、演算の順序と因数分解は、丸めのために結果に影響します。したがって、この最適化は厳密なFP動作では行われません。
GCCがこの特定の最適化を実際に行うかどうかを実際に確認したことはありません。しかし、考え方は同じです。
double
が、アプリケーションによって異なります)。注意すべきことの1つは、ffast-math最適化は必ずしも「より多くの」丸めを追加するわけではないということです。IEEEに準拠していない唯一の理由は、書かれた内容と(少しではありますが)回答が異なるためです。
x
が10より小さい場合、Mysticalの例のエラーは約10 ^ -10減少します。しかしの場合x = 10e20
、エラーは数百万になる可能性があります。
-fassociative-math
は実際に含まれている-funsafe-math-optimizations
ものであり、次に含まれているのは-ffast-math
なぜGCCが最適化さa*a*a*a*a*a
れ(a*a*a)*(a*a*a)
ないのですか?
-ffast-math
は厳密なIEEEコンプライアンスを破るだけではありません。
まず第一に、もちろん、それは壊れます厳密なIEEEコンプライアンスに違反します。たとえば、浮動小数点で数学的には(理想的には)正確に同じではないものに命令を並べ替えることができます。
次に、単一命令の数学関数の後の設定を無効にしますerrno
。これは、スレッドローカル変数への書き込みを回避することを意味します(一部のアーキテクチャでは、これらの関数に対して100%の違いが生じる可能性があります)。
第3に、すべての数学は有限であると想定しています。つまり、有害な影響を与える可能性のある場所でNaN(またはゼロ)のチェックが行われません。これが起こらないと単純に想定されています。
第4に、除算の逆近似と逆平方根を有効にします。
さらに、符号付きゼロ(ターゲットがサポートしている場合でも、符号付きゼロが存在しないとコードが想定)と丸め演算を無効にします。これにより、コンパイル時に定数の折りたたみが可能になります。
最後に、シグナリング/トラッピングの計算が原因でハードウェア割り込みが発生しないと想定するコードを生成します(つまり、ターゲットアーキテクチャでこれらを無効にできず、その結果発生しない場合、それらは処理されません)。
-ffast-math
設定-fno-数学のerrno、-funsafe-数学の最適化、-ffinite-数学のみ、-fno-丸め数学、-fno-シグナリング-nansと-fcx-limited-range。このオプションにより、プリプロセッサマクロFAST_MATHが定義されます。 "およびmath.h
math_errhandling付近などのglibcからの何か" デフォルトでは、すべての関数がerrnoと例外処理の両方をサポートします。gccの高速数学モードとインライン関数が定義されている場合、これは当てはまらない可能性があります。 "
-ffast-math
コンパイラーがいくつかのコーナーをカットし、いくつかの約束を破ることを許可します(説明されているように)。これは一般にそれ自体は危険ではなく、ほとんどの人にとって問題ではありません。ほとんどの人にとって、それは同じですが、より速いだけです。ただし、コードがこれらの約束を前提とし、それに依存している場合、コードは予想とは異なる動作をする可能性があります。通常、これはプログラムがほとんど正常に動作しているように見えることを意味しますが、一部の結果は「予期しない」可能性があります(たとえば、物理シミュレーションでは、2つのオブジェクトが正しく衝突しない可能性があります)。
-O2
サイズと速度をトレードオフするものを除いて、一般に「すべての」合法的な最適化を有効にします。-O3
サイズと速度をトレードオフする最適化も有効にします。それでも100%の正確性を維持します。-ffast-math
通常は害はないが、標準の文言では正しくないと見なされる「わずかに正しくない」動作を許可することにより、数学演算を高速化しようとします。2つのコンパイラでコードの速度が実際に大きく異なる場合(1〜2%だけではない)、コードが標準に厳密に準拠しており、...
#pragma omp parallel for
、ループ本体内では、関数の引数が指すアドレスの読み取りと書き込みの両方を行っており、かなりの量の分岐を行っています。知識のない推測として、実装で定義されたスレッドの呼び出し内からキャッシュをスラッシングしている可能性があり、MSVCは、エイリアスルールが要求する中間ストアを誤って回避する場合があります。言うことは不可能です。