Partner – Microsoft – NPI (cat=Java)
announcement - icon

Microsoft JDConf 2024 conference is getting closer, on March 27th and 28th. Simply put, it's a free virtual event to learn about the newest developments in Java, Cloud, and AI.

Josh Long and Mark Heckler are kicking things off in the keynote, so it's definitely going to be both highly useful and quite practical.

This year’s theme is focused on developer productivity and how these technologies transform how we work, build, integrate, and modernize applications.

For the full conference agenda and speaker lineup, you can explore JDConf.com:

>> RSVP Now

1. Overview

Simply put, NaN is a numeric data type value which stands for “not a number”.

In this quick tutorial, we’ll explain the NaN value in Java and the various operations that can produce or involve this value.

2. What Is NaN?

NaN usually indicates the result of invalid operations. For example, attempting to divide zero by zero is one such operation.

We also use NaN for unrepresentable values. The square root of -1 is one such case, as we can describe the value (i) only in complex numbers.

The IEEE Standard for Floating-Point Arithmetic (IEEE 754) defines the NaN value. In Java, the floating-point types float and double implement this standard.

Java defines NaN constants of both float and double types as Float.NaN and Double.NaN:

A constant holding a Not-a-Number (NaN) value of type double. It is equivalent to the value returned by Double.longBitsToDouble(0x7ff8000000000000L).”

and:

“A constant holding a Not-a-Number (NaN) value of type float. It is equivalent to the value returned by Float.intBitsToFloat(0x7fc00000).”

We don’t have this type of constants for other numeric data types in Java.

3. Comparisons with NaN

While writing methods in Java, we should check that the input is valid and within the expected range. NaN value is not a valid input in most cases. Therefore, we should verify that the input value is not a NaN value and handle these input values appropriately.

NaN cannot be compared with any floating type value. This means that we’ll get false for all comparison operations involving NaN (except “!=” for which we get true).

We get true for “x != x” if and only if x is NaN:

System.out.println("NaN == 1 = " + (NAN == 1));
System.out.println("NaN > 1 = " + (NAN > 1));
System.out.println("NaN < 1 = " + (NAN < 1));
System.out.println("NaN != 1 = " + (NAN != 1));
System.out.println("NaN == NaN = " + (NAN == NAN));
System.out.println("NaN > NaN = " + (NAN > NAN));
System.out.println("NaN < NaN = " + (NAN < NAN));
System.out.println("NaN != NaN = " + (NAN != NAN));

Let’s have a look at the result of running the code above:

NaN == 1 = false
NaN > 1 = false
NaN < 1 = false
NaN != 1 = true
NaN == NaN = false
NaN > NaN = false
NaN < NaN = false
NaN != NaN = true

Hence, we cannot check for NaN by comparing with NaN using “==” or “!= “. In fact, we should rarely use “==” or “!= ” operators with float or double types.

Instead, we can use the expression “x != x”. This expression returns true only for NAN.

We can also use the methods Float.isNaN and Double.isNaN to check for these values. This is the preferred approach as it’s more readable and understandable:

double x = 1;
System.out.println(x + " is NaN = " + (x != x));
System.out.println(x + " is NaN = " + (Double.isNaN(x)));
        
x = Double.NaN;
System.out.println(x + " is NaN = " + (x != x));
System.out.println(x + " is NaN = " + (Double.isNaN(x)));

We’ll get the following result when running this code:

1.0 is NaN = false
1.0 is NaN = false
NaN is NaN = true
NaN is NaN = true

4. Operations Producing NaN

While doing operations involving float and double types, we need to be aware of the NaN values.

Some floating-point methods and operations produce NaN values instead of throwing an Exception. We may need to handle such results explicitly.

A common case resulting in not-a-number values are mathematically undefined numerical operations:

double ZERO = 0;
System.out.println("ZERO / ZERO = " + (ZERO / ZERO));
System.out.println("INFINITY - INFINITY = " + 
  (Double.POSITIVE_INFINITY - Double.POSITIVE_INFINITY));
System.out.println("INFINITY * ZERO = " + (Double.POSITIVE_INFINITY * ZERO));

These examples result in the following output:

ZERO / ZERO = NaN
INFINITY - INFINITY = NaN
INFINITY * ZERO = NaN

Numerical operations which don’t have results in real numbers also produce NaN:

System.out.println("SQUARE ROOT OF -1 = " + Math.sqrt(-1));
System.out.println("LOG OF -1 = " +  Math.log(-1));

These statements will result in:

SQUARE ROOT OF -1 = NaN
LOG OF -1 = NaN

All numeric operations with NaN as an operand produce NaN as a result:

System.out.println("2 + NaN = " +  (2 + Double.NaN));
System.out.println("2 - NaN = " +  (2 - Double.NaN));
System.out.println("2 * NaN = " +  (2 * Double.NaN));
System.out.println("2 / NaN = " +  (2 / Double.NaN));

And the result of the above is:

2 + NaN = NaN
2 - NaN = NaN
2 * NaN = NaN
2 / NaN = NaN

Finally, we cannot assign null to double or float type variables. Instead, we may explicitly assign NaN to such variables to indicate missing or unknown values:

double maxValue = Double.NaN;

5. Conclusion

In this article, we discussed NaN and the various operations involving it. We also discussed the need to handle NaN while doing floating-point computations in Java explicitly.

The full source code can be found over on GitHub.

Course – LS (cat=Java)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are closed on this article!