programing

NaN과 달리 부동 소수점 무한대가 동일한 이유는 무엇입니까?

goodcopy 2021. 1. 14. 23:17
반응형

NaN과 달리 부동 소수점 무한대가 동일한 이유는 무엇입니까?


무한대 비교가 NaN에 적용된 논리를 따르지 않는 이유는 무엇입니까? 이 코드는 false세 번 출력됩니다 .

double a = Double.NaN;
double b = Double.NaN;
System.out.println(a == b); // false
System.out.println(a < b); //  false
System.out.println(a > b); //  false

그러나으로 변경 Double.NaN하면 동등성을 Double.POSITIVE_INFINITY얻지 true만보다 false크거나 작음 비교에 대해서는 다음과 같이됩니다.

double a = Double.POSITIVE_INFINITY;
double b = Double.POSITIVE_INFINITY;
System.out.println(a == b); // true
System.out.println(a < b); //  false
System.out.println(a > b); //  false

위험 해 보입니다. 무한한 값이 오버플로로 인해 발생한다고 가정하면 무한으로 끝나는 두 변수가 실제로 완벽한 산술에서 동일하지 않을 가능성이 더 큽니다.


당신의 추론은 Double.POSITIVE_INFINITY그것이 정확성 손실의 결과로 얻어 졌을 가능성이“가능성”이기 때문에 그 자체와 같지 않아야한다는 것입니다.

이 추론은 모든 부동 소수점에 적용됩니다. 부정확 한 연산의 결과로 유한 값을 얻을 수 있습니다. 이것은 IEEE 754 표준화위원회가 ==유한 값에 대해 항상 거짓으로 평가 하는 것으로 정의하도록 강요하지 않았습니다 . 그렇다면 왜 무한대가 달라야합니까?

정의 된대로 ==는 그것이 무엇을하는지 이해하는 사람들에게 유용합니다 (즉, 실제 계산으로 얻어야하는 값이 아니라 획득 된 부동 소수점 값을 테스트합니다 ). 그것을 이해하고 무한을 포함하지 않는 계산에도 부동 소수점을 사용하기 위해 그것을 이해해야하는 사람에게는 부동 소수점 계산 Double.POSITIVE_INFINITY == Double.POSITIVE_INFINITY의 부동 소수점 결과가 다음과 같은지 테스트하는 경우에만 true로 평가하는 것이 편리합니다. Double.POSITIVE_INFINITY.

그것은 왜 NaN이 특별한 행동을 할 수 있는지에 대한 의문을 남깁니다. 그리고 무한은 유한 값과 동일한 일반 원칙을 따라야합니다. NaN은 무한대와 다릅니다. IEEE 754 표준의 기본 원칙은 값이 정확히 그대로이지만 연산의 결과는 실제 결과에 대해 근사화 될 수 있다는 것입니다.이 경우 결과 부동 소수점 값 반올림 모드에 따라 구합니다.

1.0 / 0.0+ inf로 정의 된 순간은 잊어 버리세요 .이 논의에서는 성가신 일입니다. 의 순간을 생각 Double.POSITIVE_INFINITY만 작업의 결과로 같은 1.0e100 / 1.0e-300Double.MAX_VALUE + Double.MAX_VALUE. 이러한 연산의 경우 + inf는 유한 한 결과를 생성하는 연산과 마찬가지로 실제 결과의 가장 가까운 근사치입니다. 대조적으로 NaN은 작업이 의미가 없을 때 얻는 결과입니다. NaN이 특별히 행동하는 것은 방어 할 수 있지만 inf는 표현하기에는 너무 큰 모든 값의 근사치 일뿐입니다.

실제로, 1.0 / 0.0도 + INF를 생산하지만, 그는 예외로 간주되어야한다. 그 연산의 결과를 NaN처럼 정의하는 것이 똑같이 일관 적이었을 것입니다. 그러나 그것을 + inf로 정의하는 것이 일부 알고리즘의 구현에서 더 편리했습니다. 예는 Kahan의 노트 10 페이지에 제공됩니다 . 대부분의 사람들이 바라는 것보다 더 자세한 내용은 “복잡한 기본 기능에 대한 분기 절단 또는 아무것도 표시되지 않는 비트에 대한 많은 고충”기사에 있습니다. 또한 IEEE 754에서 NaN 플래그와 분리 된 "0으로 나누기"플래그의 존재를 NaN을 생성하는 것으로 정의되어 있지는 않지만 사용자가 0으로 나누기를 특별히 처리 할 수 ​​있다는 인식으로 해석합니다.


그것이 표준이기 때문입니다. Infinity는 Double.MAX_VALUE / -Double.MAX_VALUE보다 크거나 작은 숫자를 나타냅니다.

NaN은 의미가없는 작업의 결과를 나타냅니다. 즉, 작업이 숫자로 나오지 않았을 가능성이 있습니다.

나는 논리가 일단 숫자가 충분히 커지면 (무한대) 부동 소수점 숫자의 제한으로 인해 숫자를 추가해도 결과가 변경되지 않으므로 '유사한'무한대라고 생각합니다.

따라서 정말 큰 숫자와 비교하고 싶다면 어느 시점에서이 두 큰 숫자가 모든 의도와 목적에 충분히 가깝다고 말할 수 있습니다. 그러나 둘 다 숫자가 아닌 두 가지를 비교하려면 둘을 비교할 수 없으므로 거짓입니다. 최소한 그것들을 원시적으로 비교할 수는 없습니다.


무한대가 같은 이유는 무엇입니까? 작동하기 때문입니다.

부동 소수점 산술은 오류를 보존하는 (상대적으로) 빠른 계산을 생성하도록 설계되었습니다. 긴 계산 중에 오버플로나 다른 말도 안되는 부분을 확인하지 않는다는 생각입니다. 완료 될 때까지 기다립니다. 이것이 NaN이하는 방식으로 전파되는 이유입니다. 일단 NaN을 얻은 후에는이를 사라지게 할 수있는 작업이 거의 없습니다. 계산이 완료되면 NaN을 찾아서 문제가 있는지 확인할 수 있습니다.

무한대도 마찬가지입니다. 오버플로의 가능성이 있다면 무한대를 버리는 일을하지 마십시오.

느리고 안전하게 이동하려는 경우 IEEE-754에는 계산 결과가 NaN 또는 무한대 일 때 코드에 콜백을 제공하는 트랩 처리기를 설치하는 메커니즘이 있습니다. 대부분은 사용되지 않습니다. 일반적으로 코드가 제대로 디버깅되면 너무 느리고 무의미합니다 (쉽지 않습니다. 사람들은이 작업을 잘 수행하는 방법에 대해 박사 학위를받습니다).


"무한"값이 같다는 것을 정당화하는 또 다른 관점은 카디널리티 개념을 완전히 피하는 것 입니다. 본질적으로 "둘 다 무한하다는 점을 감안할 때 값이 다른 값과 얼마나 무한한지"에 대해 추측 할 수없는 경우라고 가정하는 것이 더 간단합니다 Inf = Inf.

편집 : 카디널리티에 대한 내 의견에 대한 설명으로 무한 수량의 비교 (또는 동등성)에 관한 두 가지 예를 제공하겠습니다.

S1 = {1,2,3, ...}무한한 양의 정수 세트를 고려하십시오 . 또한 S2 = {2,4,6, ...}무한한 짝수 정수 세트도 고려하십시오 . S2와 같이 S1의 많은 요소로 두 번 분명이 있지만 쉽게 즉, 세트 사이의 일대일 기능을 가질 수 있기 때문에, 그들은 "동등하게 많은 '요소가 1 -> 2, 2-> 4... 따라서 그들은 같은 카디 있습니다.

대신 실수 R집합과 정수 집합을 고려하십시오 I. 다시 두 가지 모두 무한 세트입니다. 그러나 각 정수 i에는 사이에 무한히 많은 실수가 (i, i+1)있습니다. 따라서 일대일 함수는이 두 세트의 요소를 매핑 할 수 없으므로 카디널리티가 다릅니다.

결론 : 무한한 수량의 동등성은 복잡하고 명령형 언어에서 쉽게 피할 수 있습니다. :)


나에게는 "0과 동일하게 행동해야하기 때문에"가 좋은 대답이 될 것 같다. 산술 오버플로와 언더 플로도 비슷하게 처리 할 수 ​​있어야합니다.

부동 소수점에 저장할 수있는 가장 큰 거의 무한대로 작은 값에서 언더 플로하면 0이되고 0은 동일한 것으로 비교됩니다.

If you overflow from the largest near-infinitely large value which can be stored in a float, you get INF, and INFs compare as identical.

This means that code which handles numbers which are out-of-scope in both directions will not require separate special-casing for one or the other. Instead, either both or neither will need to be treated differently.

And the simplest requirement is covered by the "neither" case: you want to check if something over/underflowed, you can compare it to zero/INF using just the normal arithmetic comparison operators, without needing to know you current language's special syntax for the checking command: is it Math.isInfinite(), Float.checkForPositiveInfinity(), hasOverflowed()...?


The correct answer is a simple "because the standard (and the docs) say so". But I'm not gonna be cynical because it's obvious that's not what you are after.


In addition to the other answers here, I'll try to relate the infinities to saturating arithmetic.

Other answers have already stated that the reason the comparisons on NaNs result in true, so I'm not gonna beat a dead horse.

Let's say I have a saturating integer that represents grayscale colors. Why am I using saturating arithmetic? Because anything brighter than white is still white, and anything darker than black is still black (except orange). That means BLACK - x == BLACK and WHITE + x == WHITE. Makes sense?

Now, let's say we want to represent those grayscale colors with a (signed) 1s complement 8-bit integer where BLACK == -127 and WHITE == 127. Why 1s complement? Because it gives us a signed zero like IEEE 754 floating point. And, because we are using saturating arithmetic, -127 - x == -127 and 127 + x == 127.

How does this relate to floating point infinities? Replace the integer with floating point, BLACK with NEGATIVE_INFINITY, and WHITE with POSITIVE_INFINITY and what do you get? NEGATIVE_INFINITY - x == NEGATIVE_INFINITY and POSITIVE_INFINITY + x == POSITIVE_INFINITY.

Since you used POSITIVE_INFINITY, I'll use it also. First we need a class to represent our saturating integer-based color; let's call it SaturatedColor and assume it works like any other integer in Java. Now, let's take your code and replace double with our own SaturatedColor and Double.POSITIVE_INFINITY with SaturatedColor.WHITE:

SaturatedColor a = SaturatedColor.WHITE;
SaturatedColor b = SaturatedColor.WHITE;

As we established above, SaturatedColor.WHITE (just WHITE above) is 127, so let's do that here:

SaturatedColor a = 127;
SaturatedColor b = 127;

Now we take the System.out.println statements you used and replace a and b with their value (values?):

System.out.println(127 == 127);
System.out.println(127 < 127);
System.out.println(127 > 127);

It should be obvious what this will print.


Since Double.Nan.equals (Double.NaN) was mentioned: It's one thing what should happen when you perform arithmetic and compare numbers, it's a totally different thing when you consider how objects should behave.

Two typical problem cases are: Sorting an array of numbers, and using hash values to implement dictionaries, sets, and so on. There are two exceptional cases where the normal ordering with <, = and > doesn't apply: One case is that +0 = -0 and the other is that NaN ≠ NaN, and x < NaN, x > NaN, x = NaN will always be false whatever x is.

Sorting algorithms can get into trouble with this. A sorting algorithm may assume that x = x is always true. So if I know that x is stored in an array and look for it, I might not do any bounds check because the search for it must find something. Not if x is NaN. A sorting algorithm may assume that exactly one of a < b and a >= b must be true. Not if one is NaN. So a naive sorting algorithm may crash when NaNs are present. You'd have to decide where you want NaNs to end up when sorting the array, and then change your comparison code so that it works.

Now dictionaries and sets and generally hashing: What if I use an NaN as the key? A set contains unique objects. If the set contains an NaN and I try to add another one, is it unique because it is not equal to the one that is already there? What about +0 and -0, should they be considered equal or different? There's the rule that any two items considered equal must have the same hash value. So the sensible thing is (probably) that a hash function returns one unique value for all NaNs, and one unique value for +0 and -0. And after the hash lookup when you need to find an element with the same hash value that is actually equal, two NaNs should be considered equal (but different from anything else).

That's probably why Double.Nan.equal () behaves different from ==.


This is because NaN is not a number and is therefore not equal to any number including NaN.

ReferenceURL : https://stackoverflow.com/questions/28584669/why-are-floating-point-infinities-unlike-nans-equal

반응형