決定論的と言うときは、シミュレーションを実行するたびにまったく同じ結果が得られる再現可能なシミュレーションが必要だと思います。
これを実現するには、考えられる変動の原因を見つけて排除する必要があります。
唯一の方法は、特定のアーキテクチャのバイナリにコンパイルすることです。
浮動小数点演算自体は完全に指定されています。浮動小数点標準(IEEE-754)は、すべての最新のプロセッサに準拠しており、あいまいさはありません。
2つの主なバリエーションがあります。
命令セットの違い。これは最も明白なものです。アプリケーションを32ビットまたは64ビットにコンパイルすると、わずかに異なる結果が得られる可能性があります。32ビットアプリケーションは、80ビットの中間値を使用する古いスタイルのx87命令を使用する傾向があります。これにより、一部の結果の丸めが異なります。x86でも、一度に複数のオペランドを処理するSSE命令を使用すると、違いがあります。一部のコンパイラは、オペランドがメモリ内でどのように整列されるかに依存するコードを生成する場合があります。
命令の順序の違い。数学的(a+b)+c
にa+(b+c)
は、同等です(加算は結合法則です)。浮動小数点計算では、これは当てはまりません。a
が1、b
マイナス1、およびに丸められるc
ような小さな数値の場合、式はそれぞれとに評価されます。使用する命令を決定するのはコンパイラです。言語とプラットフォームに応じて、言語コンパイラまたはジャストインタイムIL/バイトコードコンパイラの場合があります。いずれにせよ、コンパイラはブラックボックスであり、私たちの知らないうちにコードをコンパイルする方法を変える可能性があります。最小の違いは、異なる最終結果につながる可能性があります。1+c
1
c
0
丸めのアプローチは理論的には見栄えがしますが、機能しません。どのように丸めても、2つの異なるが同等の命令のセットが、異なる方法で丸められる結果を生成する場合が常にあります。
主な理由は、数字に丸めてから数字に丸めることは最初から数字に丸めることと同等ではないという意味で、丸めは構成できないというa
ことb (< a)
ですb
。例:1.49を1桁に丸めると1.5になり、それを0桁に丸めると2になります。ただし、0桁に丸めると直接1になります。
したがって、中間値に80ビットの「拡張」精度を使用するx87ベースのシステムでは、64の有効ビットから開始します。これを希望の精度に直接切り捨てることができます。倍精度の中間体がある場合、同じ中間結果が得られますが、53の有効ビットに丸められ、次に希望の精度に丸められます。
唯一のオプションは、特定のアーキテクチャ用のマシンコードを作成することです。
違いを完全になくすことではなく、違いを最小限に抑えることが目標である場合、答えは簡単です。2の累乗(1024など)で除算または乗算しても、使用する範囲に追加の丸め誤差は発生しません。アプリケーション、1000のように乗算と除算を行います。
エラーの累積をランダムウォークと見なす場合、丸めに1000を使用すると、1024を使用するよりも多くのステップが必要になります。乗算と除算の両方で追加のエラーが発生する可能性があります。したがって、平均すると、合計エラーが大きくなるため、丸め操作が間違った方向に進む可能性が高くなります。これは、すべての操作を丸めるときにも当てはまります。