Why are floating point infinities equal to NaNs?

Why doesn't infinity comparison follow logic applied to NaN? This code prints false three times:

 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 

However, if I change Double.NaN to Double.POSITIVE_INFINITY , I get true for equality, but false for comparisons more and less:

 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 

It seems dangerous. Assuming infinite values ​​are the result of an overflow, I believe it is more likely that two variables that turned out to be infinite would not really be equal in perfect arithmetic.

+53
java comparison floating-point nan infinity
Feb 18 '15 at 13:21
source share
8 answers

Your reasoning is that Double.POSITIVE_INFINITY should not be equal to itself, because it was "probably" obtained as a result of loss of accuracy.

This line of reasoning applies to all floating points. Any final value can be obtained as a result of an inaccurate operation. This did not help the IEEE 754 standardization committee determine == , as always, evaluating false for the final values, so why should the infinities be different?

As defined, == is useful for people who understand what it is doing (i.e., check the received floating point values , and, of course, not the values ​​that should have been obtained with real calculations). For those who understand this, and you need to understand that for floating-point use, even for calculations that are not related to infinity, it is convenient to use Double.POSITIVE_INFINITY == Double.POSITIVE_INFINITY to evaluate true, if only to check if the result is floating point floating point, dot calculation Double.POSITIVE_INFINITY .

This leaves the question of why NaN can afford to have special behavior, and infinities must follow the same general principles as finite ones. NaN differs from infinity: the fundamental principle of the IEEE 754 standard is that the values ​​are exactly what they are, but the result of the operation can be approximated with respect to the real result, in which case the resulting floating point value is obtained in accordance with the rounding mode .

Forget for a moment that 1.0 / 0.0 is defined as + inf, which is a nuisance in this discussion. Think at the time of Double.POSITIVE_INFINITY only as a result of operations such as 1.0e100 / 1.0e-300 or Double.MAX_VALUE + Double.MAX_VALUE . For these operations, + inf is the closest approximation of the real result, as well as for operations that lead to the final result. In contrast, NaN is the result you get when an operation does not make sense. It’s protective that NaN behaves on purpose, but inf is just an approximation of all values ​​that are too large to represent.

In fact, 1.0 / 0.0 also creates + inf, but that should be considered an exception. It would also be consistent to define the result of this operation as NaN, but defining it as + inf was more convenient in implementing some algorithms. An example is presented on page 10 in Kahan notes . More detailed information than most of them wishes is contained in the article "Branch departments for complex elementary functions or a lot of noise from nothing." . I would also interpret the existence of the “divide by zero” flag in IEEE 754, separate from the NaN flag, as a recognition that the user might want to handle division by zero specifically, although it is not defined as producing NaN.

+68
Feb 18 '15 at 13:33
source share

Because it is a standard. Infinity represents a number greater or less than Double.MAX_VALUE / -Double.MAX_VALUE.

NaN is the result of an operation that does not make sense. That is, the operation did not come out with a number.

I would suggest that logic is when a number becomes large enough (infinity) and due to the limitation of floating point numbers, adding numbers to it will not change the result, so its “like” infinity.

So, if you want to compare with really big numbers, at some point you can simply say that these two large numbers are close enough for all goals and purposes. But if you want to compare two things that are not numbers, you cannot compare them so that they are false. At least you could not compare them as a primitive.

+6
Feb 18 '15 at 13:35
source share

Why are infinities equal? Because it works.

Floating-point arithmetic is designed to create (relatively) fast calculations that save errors. The idea is that you do not check overflow or other nonsense during lengthy calculations; you wait until you're done. This is why NaNs spread the way they do: once you get NaN, you can do very little to get it gone. Once the calculation is complete, you can find NaN to verify that something went wrong.

The same goes for infinities: if there is a possibility of overflow, do not do that which will throw out infinities.

If you want to go slowly and safely, IEEE-754 has mechanisms for installing trap handlers to provide callbacks to your code when the result of the calculation is NaN or infinity. This is mostly not used; this is usually too slow and pointless once the code has been properly debugged (not so simple: people get PhD in how to do this well).

+5
Feb 18 '15 at 16:03
source share

Another perspective that justifies equal "infinite" meanings is to avoid cardinality altogether. Essentially, if you cannot reflect on “how the value is infinitely compared with the other, given that they are both infinite,” it is easier to assume that Inf = Inf .

Edit: as an explanation of my comment regarding power. I will give two examples regarding the comparison (or equality) of infinite quantities.

Consider the set of natural numbers S1 = {1,2,3, ...} , which is infinite. We also consider the set of even integers S2 = {2,4,6, ...} , which are also infinite. Although there are clearly twice as many elements in S1, as in S2, they have “equally many” elements, since you can easily have a one-to-one function between sets, i.e. 1 -> 2 , 2-> 4 , ... They have the same power.

Instead, consider the set of real numbers R and the set of integers I And again, both are infinite sets. However, for every integer I there are infinitely many real numbers between (i, i+1) . Thus, no one-to-one function can display the elements of these two sets, and therefore their power is different.

Bottomline: equality of infinite values ​​is more complicated, it is easier to avoid it in imperative languages ​​:)

+4
Feb 18 '15 at 13:46
source share

It seems to me that “because it should behave like zero” will be a good answer. Arithmetic overflow and downstream should be similar.

If you are overflowed from the largest almost infinitely small value that can be stored in the float, you get zero and the zeros are compared as identical.

If you overflow from the largest almost infinitely large value that can be stored in the float, you get INF, and INFs are compared as identical.

This means that a code that processes numbers that go beyond the scope in both directions does not require a separate special enclosure for one or another. Instead, either both or none of them will have to deal in different ways.

And the simplest requirement is covered by the case of "neither": you want to check that something is overflowed / aligned, you can compare it with zero / INF using only the usual arithmetic comparison operators, without requiring you to know your current language special command syntax validation: is it Math.isInfinite (), Float.checkForPositiveInfinity (), hasOverflowed () ...?

+3
Feb 19 '15 at 0:43
source share

The correct answer is simple: " standard (and docs ). But I'm not going to be cynical, because it is obvious that not what you need.




In addition to the other answers here, I will try to connect infinities with saturating arithmetic.

Other answers have already stated that the reason comparisons on NaN are true , so I'm not going to beat a dead horse.

Say I have a saturating integer representing shades of gray. Why am I using saturating arithmetic? Because something brighter than white is still white, and darker than black, still black (except orange ). This means BLACK - x == BLACK and WHITE + x == WHITE . Has the meaning?

Now suppose we want to represent grayscale colors with a (signed) 1s complement of an 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 since we use saturating arithmetic, -127 - x == -127 and 127 + x == 127 .

How is this related to floating point infinities? Replace the floating-point integer, 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 also use it. First we need a class to represent our saturating integer color; call it SaturatedColor and suppose 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 set above, SaturatedColor.WHITE (only WHITE above) is 127 , so let's do it here:

 SaturatedColor a = 127; SaturatedColor b = 127; 

Now we use the System.out.println statements that you used, and replace a and b with your value (values?):

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

It should be obvious that this will print.

+2
Feb 18 '15 at 16:38
source share

Since Double.Nan.equals (Double.NaN) was mentioned: This is one thing that should happen when you do arithmetic and compare numbers, this is a completely 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, etc. There are two exceptional cases when normal ordering with <, = and> is not applied: one case is that +0 = -0, and the other is NaN ≠ NaN and x <NaN, x> NaN, x = NaN false, whatever x is.

Sorting algorithms can get into a problem with this. The sorting algorithm may assume that x = x is always true. Therefore, if I know that x is stored in an array and searches for it, I probably do not do any bounds checks, because a search for it should find something. Not if x is NaN. The sorting algorithm may assume that exactly one of <b and a> = b must be true. Not if one of NaN. Thus, a naive sorting algorithm may fail in the presence of NaN. You will need to decide where you want NaN to finish when sorting the array, and then change the comparison code to make it work.

Now dictionaries and sets and hashing in general: what if I use NaN as a key? The set contains unique objects. If the collection contains NaN and I try to add another one, is it unique because it is not equal to the one that already exists? What about +0 and -0, should they be considered equal or different? There, the rule is that any two elements considered equal must have the same hash value. Therefore, it is reasonable (possibly) that the hash function returns one unique value for all NaN and one unique value for +0 and -0. And after searching for the hash, when you need to find an element with the same hash value that is actually equal, the two NaNs should be considered equal (but different from anything else).

This is probably why Double.Nan.equal () behaves different from ==.

+2
Feb 18 '15 at 17:45
source share

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

+1
Feb 18 '15 at 13:26
source share



All Articles