いいえ、これは「なぜ(1 / 3.0)* 3!= 1なのか」という別の質問ではありません。
最近、浮動小数点についてよく読んでいます。具体的には、同じ計算が異なるアーキテクチャまたは最適化設定で異なる結果をもたらす方法です。
これは、リプレイを保存する、または(サーバークライアントではなく)ピアツーピアネットワーク化されたビデオゲームの問題であり、プログラムを実行するたびにすべてのクライアントがまったく同じ結果を生成することに依存します。浮動小数点計算は、異なるマシン(または同じマシンでも!)で劇的に異なるゲーム状態につながる可能性があります。
これは、主に一部のプロセッサ(つまりx86)が倍の拡張精度を使用するため、IEEE-754に「従う」プロセッサの間でも発生します。つまり、80ビットのレジスタを使用してすべての計算を行い、64ビットまたは32ビットに切り捨てて、計算に64ビットまたは32ビットを使用するマシンとは丸めの結果が異なります。
オンラインでこの問題のいくつかの解決策を見てきましたが、すべてC ++ではなくC ++向けです。
- (Windows)、(Linux?)、または(BSD)を
double
使用して、倍精度拡張モードを無効にします(すべての計算でIEEE-754 64ビットを使用し_controlfp_s
ます)。_FPU_SETCW
fpsetprec
- 常に同じコンパイラーを同じ最適化設定で実行し、すべてのユーザーが同じCPUアーキテクチャーを持っている必要があります(クロスプラットフォームの遊びはありません)。私の「コンパイラ」は実際にはJITであるため、プログラムを実行するたびに異なる最適化が行われる可能性があります、これは可能ではないと思います。
- 固定小数点演算を使用し
float
、double
完全に回避します。decimal
この目的のためにSystem.Math
機能しますが、はるかに遅くなり、ライブラリ関数のどれもそれをサポートしません。
それで、これはC#の問題でもありますか? (Monoではなく)Windowsのみをサポートする場合はどうなりますか?
もしそうなら、私のプログラムを通常の倍精度で実行させる方法はありますか?
そうでない場合、浮動小数点計算の一貫性を保つのに役立つライブラリはありますか?
strictfp
キーワードがあり、すべての計算が拡張サイズではなく、指定されたサイズ(float
またはdouble
)で実行されます。ただし、JavaにはまだIEE-754サポートに関する多くの問題があります。非常に(非常に)非常に少数のプログラミング言語がIEE-754を適切にサポートしています。