6

すでにこの質問を読んだので、同じ入力 (同じハードウェア上で、同じコンパイラでコンパイルされた) で浮動小数点演算を使用する特定のプロセスが決定論的であるべきであると合理的に確信しています。これが正しくないケースを調べており、何が原因なのかを突き止めようとしています。

実行可能ファイルをコンパイルし、まったく同じデータを単一のマシン (非マルチスレッド) で実行していますが、約 3.814697265625e-06 のエラーが発生しています。 /4^9 = 1/2^18 = 1/262144. これは、32 ビット浮動小数点数の精度レベルにかなり近い (ウィキペディアによると約 7 桁)

私の疑いは、コードに適用された最適化と関係があるということです。Intel C++ コンパイラを使用しており、浮動小数点のスペキュレーションをセーフまたはストリクトではなく高速に変更しました。これにより、浮動小数点プロセスが非決定論的になる可能性がありますか? この動作につながる可能性のある他の最適化などはありますか?

編集: Pax の提案に従って、浮動小数点の推測を安全に変更してコードを再コンパイルしたところ、安定した結果が得られました。これにより、この質問を明確にすることができます-浮動小数点投機は実際に何をしますか?これにより、まったく同じ入力に適用されたときに同じバイナリ (つまり、1 つのコンパイル、複数の実行) が異なる結果を生成するのはなぜですか?

@Ben Intel(R) C++ 11.0.061 [IA-32] を使用してコンパイルしており、Intel クアッドコア プロセッサで実行しています。

4

2 に答える 2

13

高速モードとセーフ モードがあるほとんどすべての状況で、何らかのトレードオフが発生します。そうしないと、すべてが高速セーフモードで実行されます:-)。

また、同じ入力で異なる結果が得られた場合、プロセスは決定論的ではありません(経験的な証拠にもかかわらず)。

あなたの説明が最も可能性が高いと思います。セーフモードにして、非決定性がなくなるかどうかを確認してください。それは確かにあなたに言うでしょう。

他の最適化があるかどうかについては、同じコンパイラ/リンカーとそれらのツールへの同じオプションを使用して同じハードウェアでコンパイルしている場合、同一のコードが生成されるはずです。高速モード以外の可能性は見当たりません (または宇宙線によるメモリのビット腐敗ですが、それはほとんどありません)。

更新後:

Intel には、セーフ モードで許可されていないいくつかのことを説明するドキュメントがあります。

  • 再関連付け: (a+b)+c -> a+(b+c)
  • ゼロ折り: x + 0 -> x, x * 0 -> 0.
  • 逆数乗算: a/b -> a*(1/b).

これらの操作はコンパイル時に定義されると述べていますが、インテルのチップは非常に巧妙です。マルチ CPU セットアップでパイプラインをフルに保つために命令を並べ替えることができるため、コードでそのような動作が特に禁止されていない限り、物事は (コンパイル時ではなく) 実行時に変更され、物事がフルスピードで進行し続ける可能性があります。

これは、ベクトル化について説明しているリンクされたドキュメントの 15 ページで (簡単に) 説明されています ( 「問題: 同じプロセッサ上の同じデータで同じバイナリを再実行すると、結果が異なる」 )。

私のアドバイスは、生のうなり声または結果の完全な再現性が必要かどうかを決定し、それに基づいてモードを選択することです。

于 2009-06-09T06:27:12.953 に答える