Java Notes

Floating point equality

Don't use == and !== with floating point, but >, >=, <, <= are OK

Floating point values (double and float) should be regarded as approximations in most cases, and should be compared for equality with caution. In most cases the == and != operators should NOT be used. The relative value operators (>, >=, <, <=) will typically be appropriate to use, but you should always keep in mind that the values will only be an approximation.

Example - binary computing in a decimal world

What do you think the following will print?

double threeTenths1 = 0.3;
double threeTenths2 = 0.1 + 0.1 + 0.1;

if (threeTenths1 == threeTenths2) {
   System.out.println("Math is a world of absolute truth.");
} else {
   System.out.println("This is not logical!");
}

As you must have guessed, the two values are not equal. What happened? It's not Java's fault, but it's the nature of the binary represention of floating point numbers. Just as a fraction like 1/3 can not be expressed exactly in a fixed number of decimal digits (0.33333...), the decimal number 0.1 can not be expressed exactly in binary. Specifically, 0.110 = 0.0001100110011... where the 0011 keep repeating. But in a double or float only a fixed number of digits are kept so it must be cut off and the number is either rounded up or truncated. Either way it isn't exact. This is sad because human data is based on the decimal system.

Some sources of inexactness

This, and much more, falls into the an area of computer science known as numerical analysis. We'll ignore the causes of most of these inaccuracies, and how to avoid some of them, to concentrate on how to deal with inexactness when comparing floating point values.

Epsilon - a very small number to define an interval

A typical math idea term is epsilon, the Greek letter ε, which is used to represent a very small quantity. For the purposes of comparison, we would be satisfied to say that two floating point numbers were the same if they were within a certain value, eg, 0.00001. So we could write codes something like the following to see if two doubles were effectively "equal".

final double EPSILON = 0.00001;
. . .
if ((x >= y - EPSILON) && (x <= y + EPSILON)) . . .

Using a method to test within epsilon

If you feel comfortable using external libraries, a good one is the Apache Math library, commons.apache.org/math, which could replace the above example with the following.

import org.apache.commons.math.util.*;
. . .
static final double EPSILON = 0.00001;
. . .
if (MathUtils.equals(x, y, EPSILON)) . . .

The Apache libraries are astounding useful, but are probably overkill for a few simple tests.

NaN, Not a Number, doesn't even equal itself

What could possible go wrong with this test?

double x = someInitializedVariable;

if (x == x) {
    System.out.println("Can't fail!");
} else {
    System.out.println("Impossible?");
}

Impossible to be false? In some ideal world this might be true, but the designers of the IEEE-764 floating point standard, which is what all modern CPUs use had a great idea. They assigned a special value that represents something that is "Not a Number" (Double.NaN and Float.NaN) because it is the result of an erroneous computation, eg, dividing by zero.

All comparisons are false. Any computational operation (eg, +, -, *, /) involving a NaN as one of the operands with result in NaN. This is really quite nice because if something goes wrong with a computation it can never be made well again and you'll see the erroroneous output. But when you compare NaN against anything, the result is always false, even when you compare it with another NaN. In the previous example, the one value for which x would not equal itself would be Double.NaN.