views:

224

answers:

5

I expected the following code to produce: "Both are equal", but I got "Both are NOT equal":

float a=1.3f;
double b=1.3;
if(a==b)
{
 System.out.println("Both are equal");
}
else{
 System.out.println("Both are NOT equal");
}

What is the reason for this?

+21  A: 

It's because the closest float value to 1.3 isn't the same as the closest double value to 1.3. Neither value will be exactly 1.3 - that can't be represented exactly in a non-recurring binary representation.

To give a different understanding of why this happens, suppose we had two decimal floating point types - decimal5 and decimal10, where the number represents the number of significant digits. Now suppose we tried to assign the value of "a third" to both of them. You'd end up with

decimal5 oneThird = 0.33333
decimal10 oneThird = 0.3333333333

Clearly those values aren't equal. It's exactly the same thing here, just with different bases involved.

However if you restrict the values to the less-precise type, you'll find they are equal in this particular case:

double d = 1.3d;
float f = 1.3f;
System.out.println((float) d == f); // Prints true

That's not guaranteed to be the case, however. Sometimes the approximation from the decimal literal to the double representation, and then the approximation of that value to the float representation, ends up being less accurate than the straight decimal to float approximation. One example of this 1.0000001788139343 (thanks to stephentyrone for finding this example).

Somewaht more safely, you can do the comparison between doubles, but use a float literal in the original assignment:

double d = 1.3f;
float f = 1.3f;
System.out.println(d == f); // Prints true

In the latter case, it's a bit like saying:

decimal10 oneThird = 0.3333300000

However, as pointed out in the comments, you almost certainly shouldn't be comparing floating point values with ==. It's almost never the right thing to do, because of precisely this sort of thing. Usually if you want to compare two values you do it with some sort of "fuzzy" equality comparison, checking whether the two numbers are "close enough" for your purposes. See the Java Traps: double page for more information.

If you really need to check for absolute equality, that usually indicates that you should be using a different numeric format in the first place - for instance, for financial data you should probably be using BigDecimal.

Jon Skeet
Very nice explanation, though it is possible for a carefully crafted decimal value to fail the comparison `((float)decimalValueAsDouble == decimalValueAsFloat)`, due to a double rounding.
Stephen Canon
@stephentyrone: Yes, I suspected it might be - although I haven't come up with any examples yet.
Jon Skeet
The only thing worrying me with this post is that it somehow gives the OP the impression that he can cast and use == if he doesn't understand the comments. Someone else posted this link: http://firstclassthoughts.co.uk/java/traps/java_double_traps.html which explains it quite well.
Fredrik
@Jon Skeet: `1.0000001788139343` is such a number. In hex, its value is `0x1.000002ffffffff...`; the two closest single precision numbers are `0x1.000002` and `0x1.000004`. Rounding directly to single gives the slightly closer `0x1.000002`, whereas rounding to double gives `0x1.000003`, which is exactly half-way; when *this* value is rounded to single, the "ties to even" rule is used, and the result is `0x1.000004`.
Stephen Canon
@Fredrik, @stephentyrone: Thanks, will apply put both of these in the answer.
Jon Skeet
+2  A: 

Never check for equality between floating point numbers. Specifically, to answer your question, the number 1.3 is hard to represent in binar floating point and the souls and float representations are different.

tster
You would have gotten a +1 from me if your post wasn't filled with typos.
Mike Cooper
+11  A: 

A float is a single precision floating point number. A double is a double precision floating point number. More details here: http://www.concentric.net/~Ttwang/tech/javafloat.htm

Note: It is a bad idea to check exact equality for floating point numbers. Most of the time, you want to do a comparison based on a delta or tolerance value.

For example:

float a = 1.3f;
double b = 1.3;
float delta = 0.000001f;
if (Math.abs(a - b) < delta)
{
    System.out.println("Close enough!");
}
else
{
    System.out.println("Not very close!");
}

Some numbers can't be represented exactly in floating point (e.g. 0.01) so you might get unexpected results when you compare for equality.

bobbymcr
+2  A: 

Read this article.

The above article clearly illustrates with examples your scenario while using double and float types.

Zaki
+2  A: 
float a=1.3f;
double b=1.3;

At this point you have two variables containing binary approximations to the Real number 1.3. The first approximation is accurate to about 7 decimal digits, and the second one is accurate to about 15 decimal digits.

if(a==b) {

The expression a==b is evaluate in two stages. First the value of a is converted from a float to a double by padding the binary representation. The result is still only accurate to about 7 decimal digits as a representation of the Real 1.3. Next you compare the two different approximations. Since they are different, the result of a==b is false.

There are two lessons to learn:

  1. Floating point (and double) literals are almost always approximations; e.g. actual number that corresponds to the literal 1.3f is not exactly equal to the Real number 1.3.

  2. Every time you do a floating point computation, errors creep in. These errors tend to build up. So when you are comparing floating points / double numbers it is usually a mistake to use a simple "==", "<", etcetera. Instead you should use |a - b| < delta where delta is chosen appropriately. (And figuring out what is an appropriate delta is not always straight-forward either.)

  3. You should have taken that course in Numerical Analysis :-)

Stephen C