__Java Comparing Floating-Point Numbers__

__Problem__You want to compare two floating-point numbers for equality.

__Solution__Based on what we’ve just discussed, you probably won’t just go comparing two

floats or doubles for equality. You might expect the floating-point wrapper classes,

Float and Double , to override the equals( ) method, which they do. The equals( )

method returns true if the two values are the same bit for bit, that is, if and only if

the numbers are the same or are both NaN . It returns false otherwise, including if the

argument passed in is null, or if one object is +0.0 and the other is –0.0.

If this sounds weird, remember that the complexity comes partly from the nature of

doing real number computations in the less-precise floating-point hardware, and

partly from the details of the IEEE Standard 754, which specifies the floating-point

functionality that Java tries to adhere to, so that underlying floating-point processor

hardware can be used even when Java programs are being interpreted.

To actually compare floating-point numbers for equality, it is generally desirable to

compare them within some tiny range of allowable differences; this range is often

regarded as a tolerance or as epsilon. Example shows an equals( ) method you

can use to do this comparison, as well as comparisons on values of NaN . When run, it

prints that the first two numbers are equal within epsilon:

$ java FloatCmp True within epsilon 1.0E-7 $

Example. FloatCmp.java }/** * Floating-point comparisons. */ public class FloatCmp { final static double EPSILON = 0.0000001; public static void main(String[] argv) { double da = 3 * .3333333333; double db = 0.99999992857; // Compare two numbers that are expected to be close. if (da == db) { System.out.println("Java considers " + da + "==" + db); // else compare with our own equals method } else if (equals(da, db, 0.0000001)) { System.out.println("True within epsilon " + EPSILON); } else { System.out.println(da + " != " + db); } // Show that comparing two NaNs is not a good idea: double d1 = Double.NaN; double d2 = Double.NaN; if (d1 == d2) System.err.println("Comparing two NaNs incorrectly returns true."); if (!new Double(d1).equals(new Double(d2))) System.err.println("Double(NaN).equal(NaN) incorrectly returns false."); }

/** Compare two doubles within a given epsilon */ public static boolean equals(double a, double b, double eps) { if (a==b) return true; // If the difference is less than epsilon, treat as equal. return Math.abs(a - b) < eps; } /** Compare two doubles, using default epsilon */ public static boolean equals(double a, double b) { if (a==b) return true; // If the difference is less than epsilon, treat as equal. return Math.abs(a - b) < EPSILON * Math.max(Math.abs(a), Math.abs(b)); } }

Note that neither of the System.err messages about “incorrect returns” prints. The
point of this example with NaN s is that you should always make sure values are not
NaN before entrusting them to Double.equals( ).

## No comments:

## Post a Comment