Introduction to Programming (CPSC 124)
—Hobart & William Smith Colleges, Spring 2015
Class Notes—February 20, 2015
Home | Syllabus | Calendar | Class Notes | Labs and Projects | General Notes |

Equality Testing

Actually, we spent most of this class on loops and loop patterns, but I've moved that material into the notes from the following class (Wednesday, 09/24/2014). This set of notes is about some of the subtleties of equality tests.

If you're testing int or boolean values for equality, you can just use the == operator, and everything works as you expect.

Testing equality of double values

Because of rounding error, you should avoid checking two double values for equality using ==. It works a lot of the time, but you run in to some surprising cases, where the rounding errors cause two values that should be equal to fail the == test. For example:

System.out.println((x*x)/x == x);

will print false, though this identity is clearly valid on the real numbers. Worse, it will only do this for some values of x! Try it for x values of 0.1, 0.11, 0.2, and 0.3, for example.

In loops, this rounding error can interact with == tests to cause divergence (infinite loops) that is quite fiendish to debug. For example,

public class Sqrt { public static void main(String[] args) { double x = Double.parseDouble(args[0]); if (x >= 0) { System.out.println("sqrt(" + x + "): "); double sqX = 22.3; // "guess" while (sqX*sqX != x) { sqX = (sqX + (x / sqX)) / 2.0; System.out.println("sqX is " + sqX); } System.out.println("ours: " + sqX); System.out.println("Math.sqrt: " + Math.sqrt(x)); } else { System.out.println("sqrt("+x+") is not defined."); } } }

While this program will terminate with a correct answer on most input, it will diverge on some values that may surprise you. Try it with an input of 2, for example.

The right way is to check whether the absolute value of the difference between them is "close enough":

double EPSILON = 0.0000000000001; if (Math.abs(x-y) < EPSILON) { ... }

In class, this gave us the final version of our square root program:

public class Sqrt { public static void main(String[] args) { double x = Double.parseDouble(args[0]); if (x >= 0) { System.out.println("sqrt(" + x + "): "); double sqX = 22.3; // "guess" while (!(Math.abs(sqX*sqX - x) < 0.000000000001)) { sqX = (sqX + (x / sqX)) / 2.0; System.out.println("sqX is " + sqX); } System.out.println("ours: " + sqX); System.out.println("Math.sqrt: " + Math.sqrt(x)); } else { System.out.println("sqrt("+x+") is not defined."); } } }

Testing equality of String values

As with floating point values, you should avoid using == for equality testing for String values. It doesn't do what you think. For instance,

String s1 = "abcdef" String s2 = "abc"+"def" System.out.println(s1); // prints "abcdef" System.out.println(s2); // also prints "abcdef" System.out.println(s1 == s2); // prints false!

The problem is that String is an object type, and this means that every String value is actually an address for another location in memory where the characters of that String are stored. We'll see much more of this idea when we study study objects. For now, the thing to keep in mind is that two String values are == if and only if they are the same address in memory. Whether they have the same characters is not relevant.

The right way is to jump a little bit ahead in our material, and use the equals() method that is associated with every String value. For s1 and s2 above, this means testing either s1.equals(s2) or s2.equals(s1) (since equality of two objects, if true, is true regardless of which one we check first):

String s1 = "abcdef" System.out.println(s1.equals(s2)); // prints true

Testing equality of array values

We haven't covered arrays yet. Heads up, however, since we're going to see them in a couple of weeks: the use of == is the wrong way to check for equality of arrays, too, for the same reason it's wrong for String values. Unfortunately, there's no corresponding equals() method for arrays.


John Lasseter