19

浮動小数点の計算は、プロセッサ上で結合的でも分散的でもありません。それで、

(a + b) + cと等しくないa + (b + c)

a * (b + c)等しくないa * b + a * c

異なる結果をもたらさない決定論的浮動小数点計算を実行する方法はありますか?もちろん、ユニプロセッサでは決定論的ですが、たとえばスレッドが合計に加算される場合、スレッドのインターリーブが異なる可能性があるため、マルチスレッドプログラムでは決定論的ではありません。

だから私の質問は、マルチスレッドプログラムで浮動小数点計算の決定論的な結果をどのように達成できるかということです。

4

6 に答える 6

31

浮動小数点決定論的です。同じハードウェアで実行される同じ浮動小数点演算は、常に同じ結果を生成します。黒い魔法、ノイズ、ランダム性、ファジング、または人々が一般的に浮動小数点に帰する他のことはありません。歯の妖精は現れず、結果の低い部分を取り、枕の下に4分の1を残します。

とはいえ、大規模な並列計算に一般的に使用される特定のブロックされたアルゴリズムは、浮動小数点計算が実行される順序に関して非決定的であり、実行全体でビットが正確でない結果になる可能性があります。

あなたはそれについて何ができますか?

まず、あなたが実際にその状況に耐えられないことを確認してください。並列計算で順序付けを強制しようとする可能性のある多くのことは、パフォーマンスを低下させます。それがまさにその通りです。

また、ブロックされたアルゴリズムはある程度の非決定性をもたらす可能性がありますが、単純なブロックされていないシリアルアルゴリズムよりも丸め誤差が小さい結果をもたらすことがよくあります(驚くべきことですが本当です!)。ナイーブなシリアルアルゴリズムによって生成されたエラーを処理できる場合は、並列ブロックアルゴリズムのエラーを処理できる可能性があります。

さて、本当に、本当に、実行全体で正確な再現性が必要な場合は、パフォーマンスにあまり悪影響を与えない傾向があるいくつかの提案があります。

  1. 浮動小数点計算を並べ替えることができるマルチスレッドアルゴリズムを使用しないでください。問題が解決しました。これは、マルチスレッドアルゴリズムをまったく使用できないことを意味するのではなく、個々の結果が同期ポイント間の単一のスレッドによってのみアクセスされるようにする必要があるだけです。これを適切に実行すると、コア間のD $競合を減らすことで、一部のアーキテクチャのパフォーマンスを実際に向上させることができることに注意してください。

  2. リダクション操作では、各スレッドに結果を配列内のインデックス付きの場所に格納させ、すべてのスレッドが終了するのを待って、配列の要素を順番に蓄積することができます。これにより、少量のメモリオーバーヘッドが追加されますが、特にスレッドの数が「少ない」場合は、一般的にかなり許容できます。

  3. 並列処理を引き上げる方法を見つけます。それぞれが並列アルゴリズムを使用する24個の行列乗算を計算する代わりに、それぞれが直列アルゴリズムを使用する24個の行列積を並列に計算します。これもパフォーマンスに有益です(時には非常にそうです)。

これを処理する方法は他にもたくさんあります。それらはすべて思考とケアを必要とします。並列プログラミングは通常そうします。

于 2011-09-09T18:54:18.207 に答える
3

編集: OPの質問を誤解したようであるため、古い回答を削除しました。あなたがそれを見たいならば、あなたは編集履歴を読むことができます。

理想的な解決策は、スレッドごとに個別のアキュムレータを使用するように切り替えることだと思います。これにより、すべてのロックが回避され、パフォーマンスに大幅な違いが生じるはずです。操作全体の最後に、アキュムレータを単純に合計できます。

あるいは、単一のアキュムレータを使用することを主張する場合、1つの解決策は、浮動小数点ではなく「固定小数点」を使用することです。これは、浮動小数点型で、指数を固定値にロックするためにアキュムレータに巨大な「バイアス」項を含めることで実行できます。たとえば、アキュムレータが2 ^ 32を超えることがないことがわかっている場合は、でアキュムレータを開始できます0x1p32。これにより、基数ポイントの左側に32ビットの精度、および20ビットの小数精度(と仮定double)でロックされます。それが十分な精度ではない場合は、バイアスを小さくするか(アキュムレータが大きくなりすぎないことを前提としています)、に切り替えることができlong doubleます。long doubleが80ビット拡張フォーマットの場合、2 ^ 32のバイアスは、31ビットの小数精度を提供します。

次に、アキュムレータの値を実際に「使用」する場合は、バイアス項を減算するだけです。

于 2011-09-09T18:54:14.593 に答える
2

高精度の固定小数点データ型を使用しても、上記の方程式の結果を決定的にする問題は解決されません(特定の場合を除く)。キース・トンプソンがコメントで指摘したように、1/3は、標準の10進数または2進数の浮動小数点表現(使用される精度やメモリに関係なく)に正しく格納できない値の簡単な反例です。

特定のニーズに応じて、この問題に対処できる1つの解決策(まだ制限があります)は、有理数データ型(分子と分母の両方を格納するもの)を使用することです。キースは、そのようなライブラリの1つとしてGMPを提案しました。

GMPは、任意精度の算術演算用の無料のライブラリであり、符号付き整数、有理数、および浮動小数点数を操作します。精度に実際的な制限はありません...

それがこのタスクに適している(または適切である)かどうかは別の話です...

ハッピーコーディング。

于 2011-09-09T18:35:27.537 に答える
1

10進タイプまたはそのようなタイプをサポートするライブラリを使用してください。

于 2011-09-09T18:17:34.597 に答える
-1

各中間結果を揮発性オブジェクトに保存してみてください。

volatile double a_plus_b = a + b;
volatile double a_plus_b_plus_c = a_plus_b + c;

これは、パフォーマンスに悪影響を与える可能性があります。両方のバージョンを測定することをお勧めします。

編集:目的は、操作の順序を変更したり、中間結果をより広いレジスタに格納したりするvolatileなど、シングルスレッド環境でも結果に影響を与える可能性のある最適化を禁止することです。マルチスレッドの問題には対応していません。

EDIT2:考慮すべき他の何かはそれです

浮動式は縮小することができます。つまり、不可分操作であるかのように評価することで、ソースコードと式の評価方法によって示される丸め誤差を省略できます。

これは、を使用して抑制することができます

#include <math.h>
...
#pragma STDC FP_CONTRACT off

参照:C99標準(大きなPDF)、セクション7.12.2および6.5パラグラフ8。これはC99固有です。一部のコンパイラはそれをサポートしていない可能性があります。

于 2011-09-09T18:29:07.810 に答える
-4

パック10進数を使用します。

于 2011-09-09T18:36:36.930 に答える