F# で。ほぼ等しい同等のフロートを効率的に比較する方法は? 非常に大きな値と非常に小さな値でも機能するはずです。52 ビットの最後の 4 ビットを無視して、最初に指数を比較し、次に仮数 (仮数) を比較することを考えています。それは良いアプローチですか?float の指数と仮数を取得するにはどうすればよいですか?
2 に答える
ほぼ等しい浮動小数点値を比較する方法を尋ねるときは、次のように尋ねています。
x
浮動小数点演算で計算されたとの2 つの値がy
あるため、これらには丸め誤差が含まれており、理想的な数学値xおよびyの近似値です。浮動小数点を使用しx
て、数学的なxとyが等しいかどうかy
を比較するにはどうすればよいですか?
ここには 2 つの問題があります。
x
またはにどの程度の誤差があるかはわかりませんy
。算術演算の組み合わせによっては誤差が拡大するものもあれば、縮小するものもあります。x
との誤差はy
ゼロから無限大に及ぶ可能性がありますが、これに関する情報は提供されていません。x
とy
が等しくないが互いに近い場合、「等しい」という結果を生成することが目標であると想定されることがよくあります。これにより、偽陰性 (数学的なxとyが等しくても不等式が報告される) が陽性に変換されます。ただし、誤検知が発生します (数学的なxとyが等しくなくても、等しいと報告されます)。
これらの問題に対する一般的な解決策はありません。
- アプリケーションに関する特定の詳細を知らずに、値が等しくないはずの値が等しい、またはその逆であることをアプリケーションが許容できるかどうかを一般に知ることは不可能です。
- と にどの程度の誤差があるかを一般に知ることは不可能です。
x
y
したがって、近似的に計算された値が等しいかどうかの正しい一般的なテストはありません。
この問題は実際には等しいかどうかのテストに関するものではないことに注意してください。一般に、正しくないデータの関数を計算することは不可能です(定数関数などの自明な関数を除く)。x
およびにはエラーが含まれているため、エラーなしでlog( x ) を計算したり、エラーなしで arcosine( y ) または sqrt( xy
) を計算したりするために使用することはできません。実際、x がそうでないときに誤差が1 よりわずかに大きい場合、またはxがそうでないときにゼロよりわずかに小さい場合、 orを計算すると、理想的な数学的値が問題なく機能する場合でも、例外と NaN が生成されます。x
y
y
x
acos(y)
sqrt(x)
これが意味することは、正確な数学的演算を単純に近似浮動小数点演算に変換して、(等値をテストしているかどうかに関係なく) 良い結果が得られると期待することはできないということです。正確な算術を近似算術に変換した場合の影響を考慮し、それらがプログラムとデータにどのように影響するかを評価する必要があります。等価性の比較を含む浮動小数点演算の使用は、個々の状況に合わせて調整する必要があります。
F#float
はSystem.Double
. その場合、BitConverter.DoubleToInt64Bitsメソッドを使用して、F#値を;に効率的に (そして安全に) "キャスト" できます。ジョンがコメントで述べたように、これは の割り当てを回避するので便利です。いくつかの単純なビット演算を使用して、指数と仮数を取得できます。float
int64
byte[]
int64
ジョンが言ったように、相対的な精度を簡単にチェックしたほうがよいでしょう。これは最速のソリューションであり、多くのユース ケース (たとえば、反復ソルバーがソリューションに収束したかどうかを確認するなど) に対して「十分に近い」ものになる可能性があります。特定の精度が必要な場合は、NUnit のコードを見てください。値が期待値の特定のパーセンテージまたは ulp の数内にあることをアサートするための優れた API がいくつかあります。