2009-06-09 14 views
6

これを既に読んでいるquestion浮動小数点の算術演算を同じ入力(同じハードウェア上で、同じコンパイラでコンパイル)で使用する特定のプロセスは、決定論的。私は、これが真実ではない場合を見て、これを引き起こした原因を特定しようとしています。確定的なプロセスで浮動小数点エラーが発生する原因

私は実行可能ファイルをコンパイルしましたが、同じマシン上で(マルチスレッドではなく)実行されている同じデータを供給していますが、私が見つけた慎重なグーグルで約3.814697265625e-06のエラーが出ます実際には1/4^9 = 1/2^18 = 1/262144に等しい。これは32ビットの浮動小数点数の精度レベル(ウィキペディアによると約7桁)にかなり近いです。

疑問は、コードに適用された最適化と関係があることです。私はintel C++コンパイラを使用しており、浮動小数点投機を安全または厳密ではなく高速にしています。これは浮動小数点プロセスを非決定論的にすることができますか?この動作につながる可能性のある他の最適化などはありますか?

EDIT:Paxの提案によれば、私は浮動小数点の投機を安全に変えたコードを再コンパイルしました。私は現在安定した結果を得ています。浮動小数点スペキュレーションが実際に何をするのか、同じバイナリ(つまり、あるコンパイル、複数の実行)がまったく同じ入力に適用されたときに、どのように異なる結果を生み出すことができるのでしょうか?

@Ben私はIntel(R)C++ 11.0.061 [IA-32]を使用してコンパイルしていますが、Intelのクアッドコアプロセッサで動作しています。

+0

プロセッサプロセッサとコンパイラは何ですか? .. please – Ben

+0

どのフラグが原因であるのかわかったら、コンパイラのドキュメントをチェックするだけではどうですか? –

+0

@Tal - 私はドキュメントから何かを見つけるのが難しいです(それは速いとfpsを可能にし、安全/厳格にはそれを無効にすると言うだけです)。私はそれを理解することができますが、fpsは操作の並べ替えを可能にしますが(a * c + b * c => c *(a + b))、これらはコンパイル時の最適化であり、結果のバイナリは依然として確定的でなければならず、なぜそうでないのかを正確に知ること。 –

答えて

13

高速モードとセーフモードがあるほとんどの状況では、ある種のトレードオフがあります。そうしないと、すべてが高速安全モードで実行されます:-)。

同じ入力で異なる結果が得られた場合、プロセスはではなくであると確信しています(経験的証拠にもかかわらず)。

私はあなたの説明が最も可能性が高いと言います。それを安全モードにして、非決定論がなくなるかどうかを見てください。それは確かにあなたに伝えます。

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

  • 再アソシエーション:

    Intelがこれらに限定されないが、彼らはセーフモードで行うことを許可されていないもののいくつかを説明する文書hereがあります。 (a+b)+c -> a+(b+c)

  • ゼロ折りたたみ:x + 0 -> x, x * 0 -> 0
  • 逆数掛け算:a/b -> a*(1/b)

これらの操作がコンパイル時に定義されている間、Intelチップはかなり巧妙です。彼らはマルチCPUセットアップでパイプラインをいっぱいに保つために命令を並べ替えることができるので、コードがそのような動作を特に禁止しない限り、実行時(コンパイル時ではない)

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

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

+0

良い説明とリソースをありがとう。あなたがリンクしているこの文書では、(現在実行中のプロセス外のイベントによってグローバルスタックアドレスとアライメントが変更される可能性がある)この問題は11.xシリーズのIntelコンパイラで修正されています。しかし、私はおそらく、複数のcpusと多くのオープンなアプリケーションを実行しているときに何らかの命令が実行されているという点で、おそらく答えが得られたと思います。再度、感謝します。 –

0

プログラムが並列化されている場合、クアッドコアで実行される可能性があるため、非決定論的である可能性があります。

4つのプロセッサーが同じメモリ位置に浮動小数点値を追加したとします。そして、あなたは

(((InitialValue+P1fp)+P2fp)+P3fp)+P4fp 

または

(((InitialValue+P2fp)+P3fp)+P1fp)+P4fp 

または他の可能な順序付けのいずれかを取得する可能性があります。コンパイラは十分に良好であれば

ヘック、あなたも

InitialValue+(P2fp+P3fp)+(P1fp+P4fp) 

を取得する可能性があります。

残念ながら、浮動小数点加算は可換でも連想でもありません。実数演算はありますが、丸め、オーバーフロー、アンダーフローのため浮動小数点はありません。

このため、並列FP計算はしばしば非決定論的です。 「多くの場合」、それぞれにかかる時間が大きく異なることがあるので

on each processor 
    while(there is work to do) { 
     get work 
     calculate result 
     add to total 
    } 

のように見えるのプログラムは、非決定論的になりますので、 - あなたは、操作の順序を予測することはできません。 (スレッドがやりとりする場合はさらに悪い)

しかし、必ずしもそうではありませんが、決定的な並列プログラミングのスタイルがあるためです。

もちろん、決定論を気にする人は、問題を避けるために、整数または固定小数点数での作業です。私は特に、浮動小数点数の加算が可能なスーパーアキュムレータ、512,1024、または2048ビットの数値が好きです。丸め誤差は発生しません。


シングルスレッドアプリケーションの場合、コンパイラはコードを再配置することがあります。コンパイルごとに異なる回答が出る可能性があります。しかし、特定のバイナリは決定論的でなければなりません。

...あなたが動的言語で作業していない限り。これは、時間とともに変化するFP計算を並べ替える最適化を実行します。

そうでない限り、ItaniumにはALATのようないくつかの機能があり、シングルスレッド化されたコードでも非決定的にコード化されていました。あなたはこれらの影響を受けることはまずありません。

関連する問題