user1703055
user1703055

Reputation: 149

java Float: == equals compareTo

I have 2 questions.

1) I was told that when comparing two Float or Double data, use compareTo instead of equals. I don't know the reason. Is there any example that shows where using equals will lead something wrong?

2) See this code:

  float f2=(float)1.123450;
  Float f3=new Float(1.123450);

  System.out.println(f3==f2);   // result is true

I think using == means the two data point to the same memory address. But do f3 and f2 have the same address? Doesn't new Float(...) create a new space?

Upvotes: 4

Views: 10789

Answers (3)

alvonellos
alvonellos

Reputation: 1062

In Java, you have two (primary) types,

  1. Primitives
  2. Reference

    Primitive types are considered primitives if and only if they are of type double, float, int, long, and so on.

    Reference types are any type that uses an "Object" to store data. When you are creating in class, you're really creating a reference type "in disguise." Some examples of reference types are String, Double, Integer, and so on.

    So, as far as types go, when you compare float x to Float y, you're really comparing two different types!

    In Java, the =='s operator, most of the time, to compare only objects of equal type. Sometimes, however, the language will permit comparison of other types, such as x == y in the case that x is a primitive and y is a reference type (as defined above).

    When the comparison between x and y is performed an operation called boxing and unboxing is performed. But to understand boxing, you have to understand the difference between primitive types and reference types in terms of memory semantics. (Don't let that scare you!)

    Primitive types are stored in a memory location called the stack, which is fast and not very flexible in terms of fragmented access. It's pretty easy.

    Reference types are different though: when a reference type is instantiated using the new operator (which is called implicitly when doing Float x = <something>; -- that is, Float x = <something>; is turned into Float x = new Float(<something>);) So when a Float or other reference type is instantiated, the object is created and stored on the heap, but the pointer to that object (which is on the heap) is stored in the stack.

    This means that in order to retrieve the value that is stored in x, the computer must use the address stored on the stack, and go to that memory address in the heap.

    We use the heap to store reference types because the stack is not very good at something called "dynamic memory allocation," which is where memory is allocated and deallocated without concern to other objects around it.

    Now for boxing and unboxing:

    Boxing (also called wrapping) is the process of taking a primitive type object and storing it as a reference type (so float x becomes Float x), so that those two objects are the same type. (It's kind of like wrapping a christmas present in paper) So, behind the scenes, Integer k = 6 is a kind of boxing (autoboxing)

    Unboxing on the other hand is the opposite of unboxing, so you can call it unwrapping. Unboxing takes a "boxed" object and takes it from a reference type back to a primitive type, so the statements can work without too much hassle.:

    Integer k = 6; //Boxing

    int m = k; //Unboxing

    What this really means, in terms of your question: in the code that you posted, autoboxing and unboxing occurred, which made the statement valid. The JVM was smart enough to do what you meant -- but that doesn't mean you should make a regular habit of it, because boxing and unboxing can have a serious impact on the performance of your code!

    Also, if both x and y were Float types, you'd be comparing references!

    Good Luck!

Upvotes: 2

Peter Lawrey
Peter Lawrey

Reputation: 533492

Generally speaking == is fine unless you need to handling rounding or arithmetic errors in which case compareTo() won't help you much.

If you want to compare two doubles within an error you can use

if (Math.abs(a - b) < ERR) // within error.

or a relative error

if (Math.abs(a - b) < ERR * (Math.abs(a) + Math.abs(b))/2) // within error.

or within rounding whether the factor is often a power of ten like 10000 means to 4 decimal places.

if (Math.round(a * factor) == Math.round(b * factor)) // within a multiple

Upvotes: 8

Ted Hopp
Ted Hopp

Reputation: 234795

If both arguments were reference types, then == would test memory locations. However, if one of the arguments to == (or !=) is numeric and the other is convertible to numeric (using unboxing), then the comparison is done by comparing numerical values after unboxing. So the comparison in this case is done on the basis of the floating point values (which in this case are identical). See the Java Language Specification §15.21.1 for details.

Note, however, that Float.NaN == Float.NaN is false.

Upvotes: 13

Related Questions