C# では浮動小数点演算は一貫していますか? 可能ですか? 質問する

C# では浮動小数点演算は一貫していますか? 可能ですか? 質問する

いいえ、これは別の「なぜ (1/3.0)*3 != 1 なのか」質問。

最近、浮動小数点についてよく読んでいます。具体的には、同じ計算でも異なる結果が出る可能性がある異なるアーキテクチャや最適化設定によって異なります。

これは、リプレイを保存するビデオゲームや、ピアツーピアネットワーク(サーバークライアントとは対照的に)これは、すべてのクライアントがプログラムを実行するたびにまったく同じ結果を生成することに依存しています。1つの浮動小数点計算の小さな矛盾が、異なるマシン(または同じマシンで!

これは「追随する」プロセッサ間でも起こるIEEE-754主に一部のプロセッサ(x86)が拡張倍精度つまり、80 ビット レジスタを使用してすべての計算を実行し、その後 64 ビットまたは 32 ビットに切り捨てるため、計算に 64 ビットまたは 32 ビットを使用するマシンとは異なる丸め結果になります。

この問題に対する解決策をオンラインでいくつか見てきましたが、すべて C++ 向けであり、C# 向けではありません。

  • 倍精度拡張モードを無効にする(すべてのdouble計算でIEEE-754 64ビットを使用する)には、_controlfp_s(Windows)、_FPU_SETCW(Linux?)、またはfpsetprec(BSD)。
  • 常に同じ最適化設定で同じコンパイラを実行し、すべてのユーザーに同じCPUアーキテクチャを要求します(クロスプラットフォームプレイはありません)。私の「コンパイラ」は実際にはJITであるため、プログラムが実行されるたびに最適化が異なる可能性がある、これは不可能だと思います。
  • 固定小数点演算を使用し、floatと をdouble完全に避けてください。decimalは、この目的には機能しますが、速度が大幅に低下し、System.Mathライブラリ関数のいずれもこれをサポートしていません。

それで、これは C# でも問題になるのでしょうか?Windows のみ (Mono ではない) をサポートする場合はどうなりますか?

もしそれが、プログラムを通常の倍精度で実行するように強制する方法はありますか?

そうでなければ、役に立つ図書館はありますか?浮動小数点計算の一貫性を保ちますか?

ベストアンサー1

.net で通常の浮動小数点を決定論的にする方法は知りません。JITter は、異なるプラットフォーム (または異なるバージョンの .net) で異なる動作をするコードを作成できます。したがって、float決定論的な .net コードで通常の浮動小数点を使用することはできません。

私が検討した回避策:

  1. C# で FixedPoint32 を実装します。これはそれほど難しくありませんが (実装は半分完成しています)、値の範囲が非常に狭いため、使いにくくなります。オーバーフローしたり、精度が過度に低下したりしないように常に注意する必要があります。結局、整数を直接使用するよりも簡単ではないことがわかりました。
  2. C# で FixedPoint64 を実装します。これはかなり難しいと感じました。一部の操作では、128 ビットの中間整数が便利です。しかし、.net ではそのような型は提供されていません。
  3. カスタム 32 ビット浮動小数点を実装します。BitScanReverse 組み込み関数がないため、これを実装する際にいくつかの問題が生じます。しかし、現時点ではこれが最も有望な方法だと考えています。
  4. 数学演算にはネイティブ コードを使用します。すべての数学演算でデリゲート呼び出しのオーバーヘッドが発生します。

32 ビット浮動小数点演算のソフトウェア実装を始めたところです。2.66GHz i3 では 1 秒あたり約 7,000 万回の加算/乗算を実行できます。https://github.com/CodesInChaos/SoftFloat明らかに、まだ非常に不完全でバグが多いです。

おすすめ記事