私のコードでは、
float f = -0.0; // Negative
負のゼロと比較されます
f == -0.0f
結果はtrue
になります。
だが
float f = 0.0; // Positive
負のゼロと比較されます
f == -0.0f
また、結果はtrue
ではなくfalse
になります
なぜ両方のケースでtrueになるのですか?
これが それをテストするMCVEです(coliruでライブ) :
#include <iostream>
int main()
{
float f = -0.0;
std::cout<<"==== > " << f <<std::endl<<std::endl;
if(f == -0.0f)
{
std::cout<<"true"<<std::endl;
}
else
{
std::cout<<"false"<<std::endl;
}
}
出力:
==== > -0 // Here print negative zero
true
C++での浮動小数点演算は、多くの場合 IEEE-754 です。この基準は、実数セットの数学的定義とは異なります。
この基準 値ゼロの2つの異なる表現を定義します:正のゼロと負のゼロ 。また、これらの2つの表現は等号を比較する必要があると定義されているため、定義により、
+0.0 == -0.0
なぜそうなのかについては、その論文 すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと 、David Goldberg、1991-03(IEEE WebサイトのIEEE-754ページにリンク)は次のように書いています。
IEEE演算では、x <0のときにlog 0 =-∞を定義し、log xをNaNと定義するのが自然です。xがゼロにアンダーフローした小さな負の数を表すとします。符号付きゼロのおかげで、xは負になるため、logはNaNを返すことができます。ただし、符号付きゼロがない場合、log関数はアンダーフローした負の数を0と区別できなかったため、-∞を返す必要があります。
これは、符号付きの負のゼロmustとtrue
をゼロと比較するためです。つまり、-0.0 == 0.0
、-0f == 0f
、-0l == 0l
。
これは、C++コンパイラでサポートされている浮動小数点スキームの要件です。
(最近のほとんどのプラットフォームはIEEE754浮動小数点を使用していることに注意してください。この動作はその仕様で明示的に文書化されています。)
C++ 11は、符号付きゼロを検出できる std::signbit()
のような関数を導入し、浮動小数点間で符号ビットをコピーできる std::copysign()
を導入しました実装が符号付きゼロをサポートしている場合(IEEE浮動小数点を使用するためなど)、ポイント値。そのようなことはさておき、C++標準で参照されている符号付きゼロに言及している参照はもちろん、それらを比較した結果がどうなるかはわかりません。
C++標準は、浮動小数点表現も規定していません。これは実装定義です。
決定的ではありませんが、これらの観察は、符号付きゼロのサポート、またはそれらを比較した結果が、実装(別名コンパイラ)がサポートする浮動小数点表現によって決定されることを示唆しています。
IEEE-754は、最新の実装(つまり、コンパイラー)で使用される最も一般的な(唯一ではありませんが)浮動小数点表現です。 IEEE-758「浮動小数点演算のためのIEEE標準」セクション5.11の2番目の段落の現在の(2008年に公開された)バージョンは、(太字は私の強調)
4つの相互に排他的な関係が可能です:less than、equal、greater than 、およびunordered。最後のケースは、少なくとも1つのオペランドがNaNの場合に発生します。すべてのNaNは、unorderedを、それ自体を含むすべてのものと比較します。 比較はゼロの符号を無視します(したがって+0 = −0)。同じ符号の無限オペランドは比較します等しい。