4

FPU 制御ワードを ( を使用して_controlfp()) 変更する大規模な C++ プログラムがあります。一部の FPU 例外のマスクを解除し、SEHTranslator をインストールして型付き C++ 例外を生成します。VC++ 9.0 を使用しています。

OpenMP (v.2.0) を使用して、計算ループの一部を並列化したいと考えています。私はすでにそれを1つにうまく適用しましたが、数値結果はわずかに異なります(ただし、計算が異なる順序で実行されたことが原因である可能性があることは理解しています)。これは、FPU の状態がスレッド固有であるためだと思います。OpenMP スレッドにマスター スレッドからその状態を継承させる方法はありますか? または、新しいスレッドが正しい状態を設定する特定の関数を実行することを OpenMP を使用して指定する方法はありますか? この状況に対処するための慣用的な方法は何ですか?

4

3 に答える 3

1
  1. すでに指摘したように、double/float 操作は、数学の実数のように結合/可換/分配ではありません。特に、巨大数/極小数の掛け算/割り算では、計算の順序を変更すると、顕著な精度エラーが発生する可能性があります。

  2. 状態はレジスタとして表され、レジスタの状態 (=コンテキスト) はスレッドに固有であるため、FPU の状態はスレッド固有である必要があります。

  3. このコンテキストでは状態が明確でないため、生成されたスレッドがマスター スレッドの状態を継承すると言うのはあいまいです。登録ステータスを意味する場合は、そうではありません。

  4. 私の提案は、各スレッドごとに FPU 制御ワードを単純に設定してみませんか? たとえば、OpenMP* スレッドを生成する前、つまり並列処理の前に、_status87を使用して現在の FPU 制御ワードをグローバル変数に格納します。次に、グローバル変数を読み取り、反復のために並列に新しい値を設定するステートメントを配置します。グローバル変数では読み取り専用であるため、データ競合について心配する必要はありません。

unsigned int saved_status = _status87();
#pragma omp parallel for (...)
for (int i = 0; i < N; ++i)
{
  _controlfp(saved_status, ...);

  ..
}
于 2010-02-09T06:22:26.490 に答える
0

問題ないという結論に至りました。結果の違いは、異なるスレッドでの FPU の状態ではなく、計算の順序によるものです (精度や丸めモードは変更していません)。FPU 例外マスキングがワーカー スレッドで異なることについては、ワーカー スレッドが例外を引き起こす操作を実行した場合、その結果 (現在は NaN または Inf など) が最終的に「因数分解」されるため、これは問題ではありません。メインスレッドと例外がスローされます。

さらに、例外は、それをスローしたのと同じ OpenMP スレッドでキャッチする必要があります。これは、とにかくマスター スレッドだけが例外をスローできるようにすることを意味します。

于 2010-02-09T16:12:05.873 に答える
0

これは、浮動小数点演算の順序に関係している可能性があります。私たちは皆、操作が連想的かつ交換可能であることに依存していますが、残念なことに、浮動小数点演算は交換可能ではないため、それらを並列化すると、順序がランダム化されるため、結果が異なる場合があります。

ループを逆方向に実行して、結果が異なるかどうかを確認してください。

スレッドごとのニーズがある場合、OMP は同じスレッドに落ちるループの反復について保証します。つまり、ループがクアッド コアで 1 から N までの場合、反復 1 から N/4 は同じスレッドで実行されます。

-リック

于 2010-02-09T05:45:38.750 に答える