skip to content

Special Floating-Point Values

NaN is not equal to itself, infinities are real values, and negative zero equals zero yet is distinguishable. These properties explain most floating-point surprises, which is exactly why interviewers ask about them.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is NaN in Java, and why does NaN == NaN evaluate to false? How do you correctly test whether a value is NaN?

level: juniorimportance: must knowfreq 70%

answer

  1. NaN = Not a Number, from 0.0/0.0 or sqrt(-1)
  2. All comparisons with NaN are false; only != is true
  3. x != x is true only for NaN
  4. Use Double.isNaN / Float.isNaN to detect
  5. Wrapper equals/compare treat NaN as equal & largest (opposite of ==)

basics

~10 s

NaN means 'Not a Number' and comes from undefined operations like 0.0/0.0. It is never equal to anything, even itself, so NaN == NaN is false. Use Double.isNaN(x) to check for it.

solid answer

~40 s

NaN (Not a Number) is a special double/float value produced by mathematically undefined operations such as 0.0/0.0, Math.sqrt(-1), or Infinity - Infinity. The IEEE 754 standard requires every ordered comparison with NaN to return false, and equality (==) to return false too — including NaN == NaN. The != operator is the only one that returns true for NaN. Because of this, you cannot detect NaN with ==; the correct check is Double.isNaN(x) (or Float.isNaN). A side effect is that any collection sort, min/max, or 'x is in range' check involving NaN can silently misbehave. Note that Double.equals and the wrapper's compareTo treat NaN as equal-to-itself and greater-than-everything, which is the opposite of the primitive == behavior.

code

java · 9 lines
java
double n = 0.0 / 0.0;            // NaN
System.out.println(n == n);      // false  (!)
System.out.println(n != n);      // true
System.out.println(Double.isNaN(n)); // true — the correct check

// Wrapper / total-ordering path disagrees on purpose:
System.out.println(Double.valueOf(n).equals(Double.NaN)); // true
System.out.println(Double.compare(n, n));                 // 0 (equal)
System.out.println(Double.compare(n, 1.0));               // > 0 (NaN is largest)

go deeper

for a junior

Knows NaN comes from undefined operations and that you must use Double.isNaN, not ==.

for a middle

Explains the IEEE 754 'unordered' rule: all comparisons false, != true, and why == can't detect NaN.

for a senior

Distinguishes primitive == behavior from Double.equals/compare total ordering and the practical impact on sorting, ranges, and validation.

for a principal

Can reason about NaN as a poison/propagation value in numerical pipelines, design defensive APIs that validate inputs, and explain the equals/compareTo contract tradeoff.

## What floating-point numbers are Java's `double` (64-bit) and `float` (32-bit) store real numbers using the **IEEE 754** standard. A floating-point value is split into a sign bit, an exponent, and a mantissa (fraction). Most bit patterns represent ordinary numbers, but a few patterns are reserved for *special values*: positive/negative infinity and **NaN** (Not a Number). ## What NaN is **NaN** stands for *Not a Number*. It is the result the hardware produces when an operation has **no meaningful real-number answer**. Examples in Java: - `0.0 / 0.0` → NaN (zero divided by zero is undefined) - `Math.sqrt(-1.0)` → NaN (no real square root of a negative) - `Double.POSITIVE_INFINITY - Double.POSITIVE_INFINITY` → NaN - `0.0 * Double.POSITIVE_INFINITY` → NaN - `Math.log(-1.0)` → NaN Important: integer `0/0` does **not** produce NaN — it throws `ArithmeticException`. NaN exists only for `float`/`double`. ## Why NaN == NaN is false IEEE 754 defines NaN as **unordered**: it has no position on the number line, so it cannot be 'less than', 'equal to', or 'greater than' any value — including another NaN. The standard therefore mandates that **every ordered comparison involving NaN returns `false`**, and equality returns `false` too. The one exception is `!=`, which returns `true` (since 'not equal' is the logical negation). So: ``` NaN == NaN -> false NaN != NaN -> true // the classic idiom for 'is it NaN?' NaN < 5 -> false NaN >= 5 -> false ``` This is intentional: it lets `NaN` propagate through a computation as a poison value rather than silently looking like a normal number. ## How to correctly detect NaN Because `==` always fails on NaN, use the library helper: ```java Double.isNaN(x); // for double Float.isNaN(f); // for float ``` The old idiom `x != x` also works (it is `true` only for NaN) but is unclear; prefer `isNaN`. ## The wrapper-class twist The **primitive** `==` and the **object** comparisons disagree on purpose: - `new Double(Double.NaN).equals(Double.NaN)` → **true** - `Double.compare(Double.NaN, Double.NaN)` → **0** (equal) - `Double.compare(Double.NaN, 1.0)` → **positive** (NaN sorts as the largest value) This 'total ordering' is deliberate so that `HashMap` keys, `TreeSet`, and `Arrays.sort` behave consistently (a sort needs a consistent ordering; raw NaN comparisons would break it). So the rule to remember: **primitive comparisons treat NaN as unequal-to-everything; the boxed/`compare` paths treat NaN as equal-to-itself and largest.** ## Practical consequences - A `for` loop guarded by `x < limit` will exit immediately if `x` is NaN. - `Math.max`/`Math.min` return NaN if either argument is NaN (they propagate it). - Filtering or validating user-supplied doubles should include an explicit `isNaN` check.

  • Why do Double.equals and Double.compare treat NaN as equal to itself when == does not?
    To give a consistent total ordering so collections (TreeSet, sort, HashMap keys) and Comparable contracts work; raw NaN's unordered semantics would violate the equals/compareTo contract and break sorting.
  • What does Math.max(Double.NaN, 5.0) return?
    NaN — Math.max and Math.min propagate NaN rather than ignoring it.

saying these in an interview costs you the question

  • Thinking you can check NaN with x == Double.NaN (always false)
  • Believing integer 0/0 gives NaN (it throws ArithmeticException)
  • Assuming Double.equals matches primitive == for NaN (it doesn't)
  • Forgetting NaN poisons sorts, min/max, and range checks

context

open as a page

Why does 0.1 + 0.2 not equal 0.3 in Java, and how should you handle floating-point precision and rounding errors?

level: middleimportance: must knowfreq 75%

basics

~20 s

Doubles store numbers in binary, and 0.1, 0.2, 0.3 can't be represented exactly, so tiny rounding errors creep in: 0.1 + 0.2 is 0.30000000000000004. Never compare with == — compare within a tolerance, or use BigDecimal for money.

open as a page

How are positive and negative infinity represented in Java floating-point, and how do operations behave with them?

level: middleimportance: should knowfreq 55%

basics

~10 s

Dividing a non-zero number by zero gives infinity (Double.POSITIVE_INFINITY or NEGATIVE_INFINITY) instead of throwing. Infinity arithmetic mostly stays infinite, but undefined combos like Infinity - Infinity give NaN.

open as a page

Across NaN, infinities, and negative zero, why do Java's primitive == / < / > disagree with Double.compare and Double.equals, and what rule should you follow when implementing equals/hashCode or sorting doubles?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Primitive ==/</> follow IEEE 754: NaN is never equal (even to itself) and -0.0 equals 0.0. Double.compare/Double.equals instead define a clean total order: NaN equals itself and sorts last, and -0.0 sorts below +0.0. For equals/hashCode and sorting, use Double.compare.

open as a page

What is negative zero (-0.0) in Java? Since -0.0 == 0.0 is true, how can the two be distinguished, and when does the distinction matter?

level: seniorimportance: nice to knowfreq 30%

basics

~10 s

Floating-point has two zeros: +0.0 and -0.0. They compare equal with ==, but you can tell them apart with Double.compare or by checking 1.0/x (gives +Infinity for +0.0, -Infinity for -0.0).

open as a page