OCPJPの質問を勉強していたところ、次の奇妙なコードが見つかりました。
public static void main(String a[]) {
System.out.println(Double.NaN==Double.NaN);
System.out.println(Double.NaN!=Double.NaN);
}
コードを実行すると、次のようになりました:
false
true
互いに同じように見える2つのものを比較するときの出力false
はどうですか? NaN
はどういう意味ですか?
NaNは「数字ではない」という意味です。
オーバーフローする演算は符号付き無限大を生成し、アンダーフローする演算は非正規化値または符号付きゼロを生成し、数学的に明確な結果を持たない演算はNaNを生成します。オペランドとしてNaNを使用する数値演算はすべて、結果としてNaNを生成します。既に説明したように、NaNは順序付けられていないため、1つまたは2つのNaNを含む数値比較演算は
false
を返し、NaNを含む!=
比較はtrue
がNaNの場合のx!=x
を含むx
を返します。
定義上、NaNはNaNを含む任意の数と等しくありません。これはIEEE 754標準の一部であり、CPU/FPUによって実装されています。 JVMがサポートするロジックを追加する必要があるものではありません。
http://en.wikipedia.org/wiki/NaN
NaNとの比較は、それ自体と比較する場合でも、常に順序付けられていない結果を返します。 ...等号および不等号の述語は非シグナリングであるため、falseを返すx = xを使用して、xが静かなNaNであるかどうかをテストできます。
JavaはすべてのNaNをクワイエットNaNとして扱います。
なぜそのロジック
NaN
はNot a Number
を意味します。数字ではないものは何ですか?何でも。片方に何か、もう片方に何かを置くことができるので、両方が等しいことを保証するものは何もありません。 NaN
はDouble.longBitsToDouble(0x7ff8000000000000L)
で計算され、longBitsToDouble
のドキュメントで見ることができます:
引数が
0x7ff0000000000001L
から0x7fffffffffffffffL
の範囲または0xfff0000000000001L
から0xffffffffffffffffL
の範囲の値である場合、結果はNaN
になります。
また、NaN
はAPI内で論理的に処理されます。
ドキュメント
/**
* A constant holding a Not-a-Number (NaN) value of type
* {@code double}. It is equivalent to the value returned by
* {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
*/
public static final double NaN = 0.0d / 0.0;
ちなみに、NaN
isはサンプルコードとしてテストされています:
/**
* Returns {@code true} if the specified number is a
* Not-a-Number (NaN) value, {@code false} otherwise.
*
* @param v the value to be tested.
* @return {@code true} if the value of the argument is NaN;
* {@code false} otherwise.
*/
static public boolean isNaN(double v) {
return (v != v);
}
ソリューション
できることはcompare
/compareTo
を使用することです:
Double.NaN
は、このメソッド自体と同等であり、他のすべてのdouble
値(Double.POSITIVE_INFINITY
を含む)よりも大きいと見なされます。
Double.compare(Double.NaN, Double.NaN);
Double.NaN.compareTo(Double.NaN);
または、equals
:
this
とargument
の両方がDouble.NaN
を表す場合、Double.NaN==Double.NaN
の値はequals
であっても、true
メソッドはfalse
を返します。
Double.NaN.equals(Double.NaN);
それは質問に対する直接的な答えではないかもしれません。ただし、何かがDouble.NaN
と等しいかどうかを確認したい場合は、これを使用する必要があります。
double d = Double.NaN
Double.isNaN(d);
これはtrue
を返します
Double.NaNのjavadoc はそれをすべて言います:
タイプ
double
の非数(NaN)値を保持する定数。Double.longBitsToDouble(0x7ff8000000000000L)
によって返される値と同等です。
興味深いことに、Double
のソースはNaN
を定義します。
public static final double NaN = 0.0d / 0.0;
説明する特別な動作は、JVMに組み込まれています。
NaNは「数値ではない」ことを示す特別な値です。これは、sqrt(-1)
などの特定の無効な算術演算の結果であり、NaN != NaN
という(時々迷惑な)プロパティがあります。
浮動小数点演算のIEEE標準 倍精度数の場合、
IEEEの倍精度浮動小数点標準表現には、64ビットWordが必要です。これは、左から右に0から63までの番号で表すことができます
どこ、
S: Sign – 1 bit
E: Exponent – 11 bits
F: Fraction – 52 bits
E=2047
(すべてE
が1
であり、F
がゼロ以外の場合、V=NaN
( "Not a number")
つまり、
すべてのE
ビットが1で、F
にゼロ以外のビットがある場合、数値はNaN
です。
したがって、とりわけ、以下のすべての番号はNaN
です。
0 11111111 0000000000000000010000000000000000000000000000000000 = NaN
1 11111111 0000010000000000010001000000000000001000000000000000 = NaN
1 11111111 0000010000011000010001000000000000001000000000000000 = NaN
特に、テストすることはできません
if (x == Double.NaN)
特定の結果がDouble.NaN
に等しいかどうかを確認します。これは、すべての「数値ではない」値が個別と見なされるためです。ただし、Double.isNaN
メソッドを使用できます。
if (Double.isNaN(x)) // check whether x is "not a number"
数字ではない結果は、数字で表現できない演算の結果を表します。最も有名な操作は0/0で、その結果は不明です。
このため、NaNは何にも等しくありません(他の非数値を含む)。詳細については、ウィキペディアのページをご覧ください: http://en.wikipedia.org/wiki/NaN
これによると link には、さまざまな状況があり、覚えにくい。これは私がそれらを覚えて区別する方法です。 NaN
は、たとえば「数学的に未定義」を意味します。「0を0で割った結果は未定義」であり、「未定義に関連する比較は当然未定義」です。それに、数学的な前提のように機能します。一方、正と負の無限は事前に定義され決定的です。たとえば、「正または負の無限大は数学的に明確に定義されます」。