# 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.1_{10} = 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

- Conversion from decimal to binary (as shown above).
- Computation that produces rounding or truncation (most floating point operations).
- Adding large and small values resulting in ignoring most of the small value.
- Exceeding the range of a floating point representation.

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.