Double.NaN == Double.NaN이 false를 반환하는 이유는 무엇입니까?


155

방금 OCPJP 질문을 공부하고 있었고이 이상한 코드를 발견했습니다.

public static void main(String a[]) {
    System.out.println(Double.NaN==Double.NaN);
    System.out.println(Double.NaN!=Double.NaN);
}

코드를 실행하면 다음과 같은 결과가 나타납니다.

false
true

어떻게 출력 false우리가 서로 같은 모양 두 가지를 비교하는거야? 무슨 NaN뜻입니까?


8
정말 이상합니다. Double.NaN은 정적 최종이므로 ==와의 비교는 true를 반환해야합니다. 질문에 +1
Stephan

2
파이썬에서도 마찬가지입니다 :In [1]: NaN==NaN Out[1]: False
tdc

58
IEEE 754 표준을 올바르게 따르는 모든 언어에서 마찬가지입니다.
zzzzBov

4
직감 : "Hello"는 숫자가 아니며 true (부울)도 숫자가 아닙니다. NaN! = 같은 이유로 "Nello"! = true
Kevin

3
@Stephan :와 비교 Double.NaN==Double.NaN하면 실제로 Double.NaN유형이 true이면 true를 반환해야 합니다 java.lang.Double. 그러나 그 유형은 원시적 double이며 운영자 규칙이 double적용됩니다 (답변에 설명 된 바와 같이 IEEE 754 준수를 위해이 불평등이 필요합니다).
sleske 2012 년

답변:


139

NaN은 "숫자가 아님"을 의미합니다.

JLS (Java Language Specification) Third Edition의 내용 :

오버플로 된 연산은 부호있는 무한대를 생성하고, 언더 플로 된 연산은 비정규 화 된 값 또는 부호있는 0을 생성하며, 수학적으로 명확한 결과가없는 연산은 NaN을 생성합니다. 피연산자로 NaN을 사용하는 모든 숫자 연산은 결과적으로 NaN을 생성합니다. 이미 설명했듯이 NaN은 순서가 없으므로 NaN이 포함 된 경우를 포함하여 하나 또는 두 개의 NaN 반환 false과 NaN 반환 과 !=관련된 모든 비교가 true포함 x!=x됩니다 x.


4
@nibot : 대부분 true 입니다. IEEE 호환 플로트와 비교하면 false. 따라서 IEEE가 요구하는 표준은 Java와 다릅니다 (NAN != NAN) == false.
Drew Dormann

2
이 판도라의 상자를 열면 "IEEE가 (NAN! = NAN) == false"를 요구하는 곳은 어디입니까?
감독자

62

NaN은 정의상 NaN을 포함한 숫자와 같지 않습니다. 이것은 IEEE 754 표준의 일부이며 CPU / FPU에 의해 구현됩니다. JVM이 지원할 논리를 추가해야하는 것은 아닙니다.

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

NaN과의 비교는 자체와 비교할 때도 항상 정렬되지 않은 결과를 반환합니다. ... 항등 및 부등식 술어는 신호가 없으므로 x = x는 false를 반환하여 x가 조용한 NaN인지 테스트하는 데 사용할 수 있습니다.

Java는 모든 NaN을 조용한 NaN으로 취급합니다.


1
CPU에 의해 구현됩니까, 아니면 보헤미안에서 언급 한 것처럼 JVM에서 유선으로 연결되어 있습니까?
Naweed Chougle

3
JVM은 올바르게 구현할 것을 호출해야합니다. PC에서 CPU는 모든 작업을 수행합니다. 이 지원이없는 머신에서는 JVM이이를 구현해야합니다. (나는 그런 기계를 모른다)
Peter Lawrey

8087이 옵션이었던 당시 C 라이브러리에는 FP 에뮬레이터가 포함되어있었습니다. JVM과 같은 프로그램은 어느 쪽이든 걱정할 필요가 없습니다.
Lorne의 후작

49

왜 그 논리

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 되는 코드 샘플로 테스트 :

/**
 * 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);
}

해결책

당신이 할 수있는 일은 use compare/ compareTo:

Double.NaN이 방법으로이 값은 자체와 같고 다른 모든 double값 (포함 Double.POSITIVE_INFINITY) 보다 큽니다 .

Double.compare(Double.NaN, Double.NaN);
Double.NaN.compareTo(Double.NaN);

또는 equals:

경우 thisargument두 대표 Double.NaN, 다음 equals메소드가 리턴은 true, 비록 Double.NaN==Double.NaN값이 있습니다 false.

Double.NaN.equals(Double.NaN);

NaN != NaN거짓 인 것이 프로그램을 NaN != NaN진실한 것보다 더 복잡하게 만드는 경우를 알고 있습니까? 나는 IEEE가 오래 전에 결정을 내렸다는 것을 알고 있지만, 실용적인 관점에서, 그것이 유용한 사례를 본 적이 없다. 연속 반복이 동일한 결과를 산출 할 때까지 연산을 실행해야하는 경우, NaN 수율을 연속으로 두 번 갖는 것은 해당 동작이 아닌 종료 조건으로 "자연스럽게"감지됩니다.
supercat

@supercat 두 개의 임의의 비 숫자가 자연적으로 같다고 어떻게 말할 수 있습니까? 아니면 기본적으로 동일합니까? NaN을 기본이 아닌 인스턴스로 생각하십시오. 각각의 다른 비정상적인 결과는 이상한 것의 다른 인스턴스이며, 둘 다 동일하게 표현해야하더라도 다른 인스턴스에 ==를 사용하면 false를 반환해야합니다. 반면에 equals를 사용하면 의도 한대로 올바르게 처리 할 수 ​​있습니다. [ docs.oracle.com/javase/7/docs/api/java/lang/…
falsarella

@falsarella :이 문제는 두 개의 임의의 숫자가 "확실히 같은"것으로 간주되어야하는지의 여부가 아니라 어떤 경우에는 숫자가 자체적으로 "완전히 불평등 한"것으로 비교되는 것이 어떤 경우에 유용합니다. 하나의 한계 계산하려고하는 경우 f(f(f...f(x))), 하나 개 찾는 y=f[n](x)일부 n의 결과가되도록 f(y)에서 구별을 y한 후 y더 이상-깊게 중첩 된 결과와 구별됩니다 f(f(f(...f(y))). 하더라도 하나 원 NaN==NaN가지고, 거짓 Nan!=Nan 필요없이 적은 "놀라운 일"이 될 것이라고 거짓이 될 x!=x몇 가지 x의 사실.
supercat

1
@falsarella : 난의 종류는 생각 Double.NaN하지 않습니다 Double만, double질문의 동작에 관련된 하나입니다, 그래서 double. double값을 포함하는 동등성 관계를 테스트 할 수있는 함수가 있지만 "왜"(원래 질문의 일부)에 대해 내가 유일하게 설득력있는 대답은 "IEEE의 일부 사람들은 평등 테스트를 생각하지 않았기 때문입니다. 등가 관계 정의 " BTW, 원시 연산자 만 사용하여 테스트 x하고 y동등성 을 간결한 관용적 방법이 있습니까? 내가 아는 모든 제제는 다소 어색합니다.
supercat

1
가장 좋고 간단한 답변. 감사합니다
Tarun Nagpal

16

질문에 대한 직접적인 답변이 아닐 수도 있습니다. 그러나 무언가가 같은지 확인하려면 Double.NaN다음을 사용해야합니다.

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

이것은 돌아올 것이다 true


6

Double.NaN에 대한 javadoc은 다음과 같이 말합니다.

유형의 NaN (Not-a-Number) 값을 보유하는 상수 double입니다. 에서 반환 한 값과 같습니다 Double.longBitsToDouble(0x7ff8000000000000L).

흥미롭게도 소스 Double는 다음과 NaN같이 정의됩니다 .

public static final double NaN = 0.0d / 0.0;

설명하는 특수 동작은 JVM에 연결되어 있습니다.


5
JVM에서 하드 와이어로 연결되어 있습니까?
Naweed Chougle

4

배정 밀도 숫자의 부동 소수점 산술에 대한 IEEE 표준에 따라

IEEE 배정 밀도 부동 소수점 표준 표현에는 64 비트 워드가 필요합니다. 64 비트 워드는 0에서 63까지의 숫자로 표시 될 수 있습니다 (왼쪽에서 오른쪽으로).

여기에 이미지 설명을 입력하십시오 어디,

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

만약 E=2047(모든 E입니다 1) 및 F다음 제로가된다 V=NaN( "숫자가 아님")

즉,

모든 E비트가 1이고 0이 아닌 비트가 있으면 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

NaN은 "숫자가 아님"을 나타내는 특수 값입니다. 와 같은 특정 잘못된 산술 연산의 결과이며 sqrt(-1)(때로는 성가신) 속성이 NaN != NaN있습니다.


2

숫자가 아닌 숫자로 결과를 표현할 수없는 연산의 결과를 나타냅니다. 가장 유명한 연산은 0/0이며 결과는 알려져 있지 않습니다.

이러한 이유로 NaN은 다른 숫자가 아닌 값을 포함하여 어떤 것과도 같지 않습니다. 자세한 내용은 wikipedia 페이지를 확인하십시오. http://en.wikipedia.org/wiki/NaN


-1 : 의 결과를 나타내지 않습니다0/0 . @N 0/0은 항상 NaN이지만 NaN은 @AdrianMitev의 답변에 따라 2+NaN다음 과 같은 다른 작업의 결과 일 수 있습니다.an operation that has no mathematically definite result produces NaN
ANeves

실제로 NaN은 "숫자가 아님"을 나타내며 정의되지 않거나 표현할 수없는 값을 갖는 모든 작업의 ​​결과입니다. 가장 유명하고 일반적인 작업은 0/0이지만 분명히 동일한 결과를 나타내는 수많은 다른 작업이 있습니다. 내 대답이 향상 될 수 있다는 데 동의하지만 -1에 동의하지 않습니다 ... Wikipedia에서도 NaN 결과가있는 작업의 첫 번째 예로 0/0 작업을 사용한다는 것을 확인했습니다 ( en.wikipedia.org/wiki/ NaN ).
Matteo

또한 이것은 Double의 Java 소스에 있습니다. public static final double NaN = 0.0d / 0.0;
기 illa

1
@Matteo +0, 이제 거짓 진술이 사라졌습니다. 내 -1 또는 +1은 귀하가 동의하거나 동의하지 않습니다. 그러나 저자가 자신의 답변이 왜 유용하지 않은지 이해하고 원하는 경우 변경할 수 있도록 -1로 주석을 남기는 것이 좋습니다.
ANeves

@Guillaume이 그 의견이 저에게 의미가 있다면, 다시 말 해주세요 : 이해가되지 않습니다.
ANeves

0

링크 에 따르면 다양한 상황이 있으며 기억하기가 어렵습니다. 이것이 내가 그들을 기억하고 구별하는 방법입니다. NaN"수학적으로 정의되지 않음"을 의미합니다. 예 : "0을 0으로 나눈 결과는 정의되지 않습니다". 정의되지 않았기 때문에 "정의되지 않은 관련 비교는 물론 정의되지 않았습니다". 게다가, 그것은 수학적 전제와 비슷하게 작동합니다. 한편, 양의 무한대와 음의 무한대 모두 미리 정의되고 결정적입니다. 예를 들어 "양 또는 음의 무한대는 수학적으로 잘 정의되어 있습니다".

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.