How do == and the relational operators behave when comparing primitive values, including mixed numeric types?
answer
- Primitives: == is value, relational is magnitude
- Mixed types -> binary numeric promotion to the wider type
- char is numeric: 'A' == 65
- 0.1 + 0.2 != 0.3 (use epsilon)
- NaN != NaN is true; NaN == NaN is false
basics
~20 sFor primitives, == checks if the two values are equal and the relational operators compare their size. If the two operands are different number types, the smaller one is converted up to the larger type before comparing.
solid answer
~40 sOn primitives, == and != compare the actual values, and <, <=, >, >= compare magnitude — all yielding a boolean. When the two operands have different numeric types, Java applies binary numeric promotion: both are widened to the larger type before the comparison. So comparing an int with a long promotes the int to long; comparing anything with a double promotes to double. char participates as its numeric code unit, so 'A' == 65 is true. Two important traps: floating-point == is unreliable because values like 0.1 + 0.2 don't equal 0.3 exactly, so you compare within an epsilon; and NaN is never equal to anything, even itself, so Double.NaN == Double.NaN is false while NaN != NaN is true.
go deeper
Knows == compares primitive values and relational operators compare size.
Explains binary numeric promotion for mixed types and that char is numeric.
Articulates the floating-point and NaN/signed-zero edge cases and the primitive-vs-wrapper inconsistency.
Reasons about IEEE 754 semantics, when to forbid float == in code review, and how NaN propagation can break loop guards and sort contracts.
## Comparing primitives by value A **primitive** holds its value directly. For the numeric primitives (`byte`, `short`, `int`, `long`, `float`, `double`) plus `char`, the operators do exactly what you'd expect: - `==` / `!=` test whether the stored values are equal / unequal. - `<`, `<=`, `>`, `>=` test relative magnitude. All of them return a `boolean`. ## Binary numeric promotion (mixed types) When the two operands are *different* numeric types, Java first converts them to a common type — this is called **binary numeric promotion**. The rule (simplified): if either operand is `double`, both become `double`; else if either is `float`, both become `float`; else if either is `long`, both become `long`; otherwise both become `int`. Types narrower than `int` (`byte`, `short`, `char`) are always promoted at least to `int`. ```java int i = 65; long l = 65L; System.out.println(i == l); // true: i is promoted to long char c = 'A'; System.out.println(c == 65); // true: 'A' has code unit 65, promoted to int ``` ## char is numeric `char` stores a 16-bit Unicode **code unit** — effectively an unsigned number. So you can compare chars with `<` (alphabetical-ish ordering by code point) and compare a char to an int. ## Trap 1 — floating-point equality `float` and `double` use **IEEE 754** binary representation, which cannot represent most decimal fractions exactly. So: ```java System.out.println(0.1 + 0.2 == 0.3); // false — the sum is 0.30000000000000004 ``` The fix is to compare within a small tolerance (**epsilon**): ```java Math.abs((0.1 + 0.2) - 0.3) < 1e-9; // true ``` ## Trap 2 — NaN **NaN** ("Not a Number", produced by e.g. `0.0/0.0` or `Math.sqrt(-1)`) is special: by the IEEE 754 rule, NaN compares *unequal* to everything, including itself. ```java double n = Double.NaN; System.out.println(n == n); // false! System.out.println(n != n); // true — the idiom to detect NaN ``` Use `Double.isNaN(n)` to test for it cleanly. Note `Double.compare` and `equals` on the *wrapper* treat NaN as equal to itself — different rule from the primitive `==`. ## Trap 3 — signed zero With the primitive `==`, `0.0 == -0.0` is `true`, but `Double.compare(0.0, -0.0)` returns a positive number (treats them as distinct). Rarely matters, but it's the mirror image of the NaN inconsistency. ## Why it matters Getting promotion right explains why `'A' == 65` is true; knowing the floating-point and NaN rules prevents flaky comparisons and infinite loops where a NaN guard never becomes false.
- What is the idiomatic way to detect a NaN, and why not use == ?Use Double.isNaN(x). You cannot use x == Double.NaN because NaN is unequal to everything, so that comparison is always false; the only == trick is x != x, but isNaN is clearer.
- Does 0.0 == -0.0 return true?Yes for the primitive == operator. But Double.compare(0.0, -0.0) reports them as different, and the same holds for Double.equals — a deliberate inconsistency.
saying these in an interview costs you the question
- Comparing floating-point values with == and expecting exactness
- Thinking NaN == NaN is true
- Claiming you cannot compare an int with a long directly