web-dev-qa-db-ja.com

Double.NaN == Double.NaNがfalseを返すのはなぜですか?

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はどういう意味ですか?

151
Maverick

NaNは「数字ではない」という意味です。

Java言語仕様(JLS)第3版が言う

オーバーフローする演算は符号付き無限大を生成し、アンダーフローする演算は非正規化値または符号付きゼロを生成し、数学的に明確な結果を持たない演算はNaNを生成します。オペランドとしてNaNを使用する数値演算はすべて、結果としてNaNを生成します。既に説明したように、NaNは順序付けられていないため、1つまたは2つのNaNを含む数値比較演算はfalseを返し、NaNを含む!=比較はtrueがNaNの場合のx!=xを含むxを返します。

136
Adrian Mitev

定義上、NaNはNaNを含む任意の数と等しくありません。これはIEEE 754標準の一部であり、CPU/FPUによって実装されています。 JVMがサポートするロジックを追加する必要があるものではありません。

http://en.wikipedia.org/wiki/NaN

NaNとの比較は、それ自体と比較する場合でも、常に順序付けられていない結果を返します。 ...等号および不等号の述語は非シグナリングであるため、falseを返すx = xを使用して、xが静かなNaNであるかどうかをテストできます。

JavaはすべてのNaNをクワイエットNaNとして扱います。

60
Peter Lawrey

なぜそのロジック

NaNNot a Numberを意味します。数字ではないものは何ですか?何でも。片方に何か、もう片方に何かを置くことができるので、両方が等しいことを保証するものは何もありません。 NaNDouble.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;

ちなみに、NaNisはサンプルコードとしてテストされています:

/**
 * 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

thisargumentの両方がDouble.NaNを表す場合、Double.NaN==Double.NaNの値はequalsであっても、trueメソッドはfalseを返します。

Double.NaN.equals(Double.NaN);
48
falsarella

それは質問に対する直接的な答えではないかもしれません。ただし、何かがDouble.NaNと等しいかどうかを確認したい場合は、これを使用する必要があります。

double d = Double.NaN
Double.isNaN(d);

これはtrueを返します

14
JREN

Double.NaNのjavadoc はそれをすべて言います:

タイプdoubleの非数(NaN)値を保持する定数。 Double.longBitsToDouble(0x7ff8000000000000L)によって返される値と同等です。

興味深いことに、DoubleのソースはNaNを定義します。

public static final double NaN = 0.0d / 0.0;

説明する特別な動作は、JVMに組み込まれています。

6
Bohemian

NaNは「数値ではない」ことを示す特別な値です。これは、sqrt(-1)などの特定の無効な算術演算の結果であり、NaN != NaNという(時々迷惑な)プロパティがあります。

3
Fred Foo

浮動小数点演算のIEEE標準 倍精度数の場合、

IEEEの倍精度浮動小数点標準表現には、64ビットWordが必要です。これは、左から右に0から63までの番号で表すことができます

enter image description here どこ、

S: Sign – 1 bit
E: Exponent – 11 bits
F: Fraction – 52 bits 

E=2047(すべてE1であり、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"
3
Sufiyan Ghori

数字ではない結果は、数字で表現できない演算の結果を表します。最も有名な操作は0/0で、その結果は不明です。

このため、NaNは何にも等しくありません(他の非数値を含む)。詳細については、ウィキペディアのページをご覧ください: http://en.wikipedia.org/wiki/NaN

2
Matteo

これによると link には、さまざまな状況があり、覚えにくい。これは私がそれらを覚えて区別する方法です。 NaNは、たとえば「数学的に未定義」を意味します。「0を0で割った結果は未定義」であり、「未定義に関連する比較は当然未定義」です。それに、数学的な前提のように機能します。一方、正と負の無限は事前に定義され決定的です。たとえば、「正または負の無限大は数学的に明確に定義されます」。

0
Tiina