9

I am confused about the behavior of floating point number after seeing the result of following code snippet.

    float var1 = 5.4f;
    float var2 = 5.5f;

    if(var1 == 5.4)
        System.out.println("Matched");
    else
        System.out.println("Oops!!");

    if(var2 == 5.5)
        System.out.println("Matched");
    else
        System.out.println("Oops!!");

Output:

Oops!!
Matched

Is this because of decimal number that can't be represent exactly in base 2 binary format? OR Is this because of precision as I comparing a float type variable with a double type? If yes then why it works fine for next variable?

  • Plenty of information, just google around :) Firstly, use double over float, and also see `BigDecimal`... – vikingsteve Sep 19 '13 at 06:55
  • possible duplicate of [Comparing float and double primitives in Java](http://stackoverflow.com/questions/7392167/comparing-float-and-double-primitives-in-java) – devnull Sep 19 '13 at 06:58
  • Another question discusses this really well http://stackoverflow.com/questions/1088216/whats-wrong-with-using-to-compare-floats-in-java – AurA Sep 19 '13 at 07:03

5 Answers5

16

Is this because of decimal number that can't be represent exactly in base 2 binary format?

Yes. Basically, 5.4f and 5.4d are not the same, because neither of them are exact representations of 5.4.

5.5f and 5.5d are the same because they're both exact representations of 5.5.

Note that 5.4 is implicitly the same as 5.4d - the default type for a floating point literal is double. Any use of a binary operator with operands of float and double will promote the float to a double and perform the operation on two double values.

It may make things easier to think of it in terms of decimal types. Suppose we had two types, Decimal5 and Decimal10 which are decimal numbers with 5 or 10 significant figures. Then consider "a third" and "a quarter":

A third:
Decimal5:  0.33333
Decimal10: 0.3333333333

A quarter (showing trailing zeroes just for clarity):
Decimal5:  0.25000
Decimal10: 0.2500000000

When comparing the Decimal5 value closest to a third with the Decimal10 value, the Decimal5 value would be converted to a Decimal10 value of 0.3333300000, which doesn't equal 0.3333333333. This is similar to your first example.

When comparing the values for a quarter, however, the Decimal5 value of 0.25000 is converted to 0.2500000000, which is the same as the Decimal10 value we have for a quarter. This is similar to your second example.

Of course the binary floating point types are a bit more complicated than that, with normalization, subnormal numbers etc - but for the purposes of your example, this analogy is close enough.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • in fact, there is one more point that is not discussed. when you do if (var1 == 5.4) what is really happening? It looks like that the var1 gets implicitly cast to double and compared to 5.4d. – thang Sep 19 '13 at 08:02
  • @thang: Yes - I did sort of discuss that in my analogy, showing that a Decimal5 value is converted to a Decimal10 value. – Jon Skeet Sep 19 '13 at 08:04
  • Well there is something specific I am getting at, which is within the if (var1 == 5.4), what happens? this is specific to how java handles 5.4. why does it not cast 5.4 to float implicitly? your analogy just demonstrates that 5.4f and 5.4d are not the same, but why does 5.4f and 5.4d not being the same cause that if to be false. – thang Sep 19 '13 at 08:26
  • @thang: Because it's a literal without the `f`, which means it's implicitly a `double`. I've edited that into the answer. – Jon Skeet Sep 19 '13 at 08:27
  • yeah i know. i was trying to get you to put it into the answer so the next person who reads it can understand. cool though. i would also add that it automatically "promotes" the float variable var1 to a double. – thang Sep 19 '13 at 09:25
  • @thang: Right, added the bit about promotion. – Jon Skeet Sep 19 '13 at 10:03
6

The difference is that 5.5 can be represented exactly in both float and double - whereas 5.4 can't be represented exactly.
reference http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Prabhaker A
  • 8,317
  • 1
  • 18
  • 24
3

Replace your if condition with:

if(var1 == 5.4f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

if(var2 == 5.5f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

Then it will print Matched both times. Reason is because without qualifier f in the end Java treats 5.4 as double which cannot be represented accurately in comparison to 5.5.

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • From the question it is clear that the asker knows the difference between adding a trailing "f" and leaving it. His question was why one of the float was equal with its double counter part and the other is not. @Jon Skeet has answered it correctly. – Andromeda Sep 19 '13 at 07:04
2

It's easy to see:

if(var1 == 5.4f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

if(var2 == 5.5f)
    System.out.println("Matched");
else
    System.out.println("Oops!!");

Output:

Matched
Matched

The binary representation of 5.4f and 5.4d is not exactly the same

Rafi Kamal
  • 4,522
  • 8
  • 36
  • 50
  • Pedantic: the binary representation of 5.5f and 5.5d are also not the same (as in if you were to compare memory directly). What you probably meant to say is that the actual number presented by the binary representation of 5.4f and 5.4d are not the same. – thang Sep 19 '13 at 07:03
0

If you want to compare floating point types, you must use comparing with epsilon. Here you can see all the ways you can use for comparing floating point types.

Darwing
  • 833
  • 1
  • 12
  • 23