5

2 つの「実数」を比較して等しいかどうかを判断するとき、なぜ == 演算子を使用してはならないのですか? 代わりに何を使用する必要がありますか?

強制とキャスティングの違いは何ですか? キャストとは、値を次のように別の型にすることを強制するときであるというのが私の一般的な仮定です。

int n = 9;
return double(n)/5;
4

5 に答える 5

4

最初の質問に直接答えるには: 「[なぜ] == 演算子を使用すべきではないのですか?」その答えは、以前の操作で丸め誤差が発生したためであり、一般に、正しくないデータに適用された関数の正しい結果を計算することは不可能です。値を計算xし、yそのモデルが正確な数学的値xおよびyであるがxy丸め誤差の影響を受けている場合、xがyに等しいかどうかを示すxand の関数はありません。y

これは、これらの状況でxがyに等しいかどうかを計算できないことを意味します。問題なのはオペレーターではありません。(実際には、常にまったくエラーなしで計算される数少ない浮動小数点演算の 1 つです。入力が与えられると、常に正確に正しい結果が返されます。) 問題は、この間違った値から正しい答えを返す関数がないことです。入力。(そして、これは だけの問題ではありません。丸め誤差のある がある場合、それを使用して計算されたほとんどすべての関数にエラーが含まれます。エラーが発生し、エラーが発生します。さらに悪いことに、誤って負または======xsqrt(1-x*x)acos(x)1-x*xx誤って 1 より大きい可能性があります)。

次に、「代わりに何をしますか?」という質問になります。</p>

比較が真または偽を報告するかどうかの「ごまかし」は、プログラムに新しいエラーをもたらします。問題は、アプリケーションで許容できるエラーはどれかということです。2 つの数値が正確な数学では等しくないときに等しいと比較で報告された場合、それは許容されますか、それとも許容できませんか? 比較の結果、2 つの数値が等しくなるはずなのに等しくないと報告された場合、それは受け入れられるか受け入れられないか?

これらの質問に対する答えは、プログラムによって異なります。一般に、考慮すべき事項は複数あります。

  • 比較されている値にすでにどの程度の誤差が存在する可能性がありますか?
  • 正確な値が異なる場合、どのような場合に比較レポートが正しいと認められますか?
  • 正確な値が等しい場合、どのような場合に、比較レポートが偽であっても問題ありませんか?

上記の質問に対する答えはアプリケーションごとに異なるため、 の代わりに何を使用するかについて一般的な答えはありません==。アプリケーションによっては、相対的な許容差を比較に使用できる場合もあれば、絶対的な許容差を使用できる場合もあれば、別のものが必要な場合もあります。また、一部のアプリケーションでは、値に誤差があるため、比較を受け入れられない場合があります。このような場合、計算を再設計してエラーを減らすか、他の解決策を見つける必要があります。

そう:

  • 相対的または絶対的な公差と比較するためのアドバイスには注意してください。公差の使用が許容されるかどうかは、アプリケーションによって異なります。一般的なルールはありません。どの程度の公差が許容されるかは、アプリケーションによって異なります。一般的なルールはありません。
  • 許容できる解があるかどうかは、計算値のエラーによって異なります。エラーが大きすぎて解決できない場合があります。公差の大きさに関する一般的な推奨事項に注意してください。浮動小数点エラーはゼロから無限大まで変化する可能性があり、状況に依存するため、機能する一般的な許容誤差はありません。
  • だけでなく、エラーのあるデータから計算されたすべての関数がエラーになることに注意してください==
于 2013-05-13T13:25:55.777 に答える
4

== 演算子を使用してはいけないのはなぜですか?

うまくいかないかもしれないからです。しかし==、問題なのはオペレーターではありません。問題は数字そのものです。一部の浮動小数点数は正確な 2 進数表現を持たず、浮動小数点演算は正確ではありません。たとえば、次のような単純な値は0.2、2 進浮動小数点数を使用して正確に表現することはできず、浮動小数点数の精度が限られているため、操作の順序を少し変更すると結果が変わる可能性があります。コンパイラや CPU アーキテクチャが異なると、一時的な結果が異なる精度で格納されるため、環境の詳細によって結果が異なります。

計算を行い、その結果を何らかの期待値と比較すると、意図したとおりの結果が得られる可能性はほとんどありません。

つまり、計算を行ってからこの比較を行うと、次のようになります。

if (result == expectedResult)

その場合、比較が真になる可能性は低いです。比較が真の場合、おそらく不安定です。入力値、コンパイラ、または CPU のわずかな変更によって結果が変化し、比較が偽になる可能性があります。

したがって、浮動小数点数の比較はコンテキストに依存します。操作の順序を変更しても結果が異なる可能性があるため、数値をどの程度「等しく」したいかを知ることが重要です。これはイプシロンと呼ばれます。

考慮すべき点は複数あります。

  • 比較対象の値にすでに存在するエラーに対する許容度はどのくらいですか?
  • H0: 正確な値が異なる場合、どのような場合に
    比較レポートが正しいと認められますか?
  • H1: 正確な値が等しい場合、どのような場合に、比較が偽であると報告しても問題ありませんか?

混乱とエラーの原因は、比較ではなく、比較される数値そのものです。実際==、演算子は信頼できます - 実際の引数を取って常に正しい答えを返します。

Bruce Dawson による浮動小数点数の比較は、浮動小数点数の比較を検討する際の出発点として適しています。
すべてのプログラマーが浮動小数点演算について知っておくべきことは、もう 1 つの非常に優れた記事です。

経験則。

次の定義は、Knuth による The art of computer programmingからのものです。

bool approximatelyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool essentiallyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyGreaterThan(float a, float b, float epsilon)
{
    return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyLessThan(float a, float b, float epsilon)
{
    return (b - a) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

イプシロンの選択はコンテキストに依存し、数値をどの程度等しくするかを決定します。


強制

これは暗黙のキャストであるため、明示的に (直接) 指定しないと発生します。自動です

    double f(int i){ 
    return i;
    } <- coersion int to double

double  d;
long    l;
int     i;

if (d > i)   d = i; // <-coersion
if (i > l)   l = i; // <-coersion
if (d == l)  d *= 2; // <-coersion

鋳造

あなたはそれを明示的に使用します、あなたは言います

static_cast<>()
dynamic_cast<>()
const_cast<>()
reinterpret_cast<>()

これらにはそれぞれ異なる特殊な意味があります。つまり、多相dynamic_cast型に適し、タイプセーフであるため、ポインター (または Base& 参照) を安全に (または Derived&) に変換するために使用します。実際のオブジェクトがまさにあなたのものであるかどうかをテストします。であることを期待しています。のターゲットはポリモーフィックである必要はありません - これにより、特別なタイプの送信が可能になります (具体的なオブジェクトをポリモーフィックなタイプでラップし、後で再び具体的なオブジェクトにアンラップします [Bjarne Stroustrup C++ を参照...、15.4.1 Dynamic_cast、p. 408])。はポインター変換に使用され、ポインターは多相型 (つまり、仮想関数を持つクラス) を指す必要はなく、実行時に型を検査しません。Base*Derived*dynamic_castreinterpret_caststatic_castdynamic_casttype_infoキャストされているオブジェクトに関連付けられていることを確認する必要があります。

ただし、指しているメモリに関する追加情報を必要としないため、static_castからのみキャストできます。また、失敗すると実行時エラーが発生しますが、参照がキャストされている場合はポインターが返されるか、例外がスローされるvoid*ことも非常に重要です。constnessをorでキャストすることはできないため、どちらconstnessを尊重すると言われています。どちらもアクセス制御を尊重します(プライベートベースにキャストすることはできません[派生クラスメソッドのみが可能であり、クラスのメソッドがこの{フレンド宣言はベースにある}のフレンドであるため]))static_castdynamic_cast0bad_castconst_castdynamic_caststatic_castDerived* -> Base*

于 2013-05-13T02:04:08.570 に答える
2

この記事浮動小数点数の比較は、浮動小数点数の比較について詳しく説明しており、このWhat Every Programmer Should Know About Floating-Point Arithmeticもよく読んでください。

とこの SO スレッドの違いに関してキャストcoercion強制の違いは何ですか? 一方、C++ に固有のものではありませんが、質問を十分にカバーしています。基本的には暗黙的ですが、明示的です。castingcoercioncasting

于 2013-05-13T01:54:55.257 に答える
-1

答えではなく、理由の背景だけです(コメントには収まりません):

float と double は Binary として内部的に保存されます。2 進小数点の左側の 1 が 1、2、4、8、16 のように、2 進小数点の右側の数値は 1/2、1/4、1/8、1/16、 ... 10 進数 1.5 は 2 進数 1.1、10 進数 1.25 は 2 進数 1.01 です。

しかし、10 進数で 1.1 のような数は、実際には 2 進数では無理数です。これは、数値の計算方法を少し変更すると、わずかに異なる結果が得られることを意味します。

正確な答えが必要な場合は、BigDecimal を使用できます。バイナリを使用して数値を格納するのではなく、毎回正確な答えが得られるため、自信を持って .equals() を使用できます。

于 2013-05-13T07:15:29.373 に答える