Prateek
Prateek

Reputation: 1926

Float in java generating unexpected output

I was writing a sample program with floats but suddenly something weird happened. I would really appreciate if someone can shed some light on why I am facing such behavior from my program.

package Programs;

public class FloatTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        float f1 = (float) 3.2;
        float f2 = (float) 6.5;
        if (f1 == 3.2) {
            System.out.println(f1 + " same");
        } else {
            System.out.println(f1 + " different");
        }
        if (f2 == 6.5) {
            System.out.println(f2 + " same");
        } else {
            System.out.println(f2 + " different");
        }
    }
}

Output:

3.2 different
6.5 same

After doing some tests with changing values of f2 I noticed that I get unexpected result for f2 > 3.5 Why is that? Any input is really appreciated.

Thanks

Upvotes: 2

Views: 480

Answers (6)

Gregory Bishop
Gregory Bishop

Reputation: 2017

:) Ahh IEEE754, and JVM differences with floats. In brief 6.5 is not the same as the float value of 6.5. 6.5 == 6.5f will work, but you better understand what you are doing! Please read http://en.wikipedia.org/wiki/IEEE_floating_point, also note the 'strictfp' keyword for force IEEE754 behavior across platforms. There are many things to consider here, rounding behavior, order of precidence, JVM differences, etc. Things that arent integers or longs are unexpectedly tricky.

You are manipulating a binary representation of a number which has a precision that is appropariate for many types of mathematical calculations where a infinately precise answer is not required. For many Engineering and Financial systems, especially for those involving multiplication or fractions this is NOT ACCEPTABLE. You either need to rebase your accounting (using a financial class that understands money and decimals), (for instance counting in pennies for money), and for engineering you may need to use BigDecimal or a related class with specific rounding behavior, percision, etc.

To give another example the float value of 1/3 + 1/3 + 1/3, may or may not be equal to 1. Because the 1's and 0's that make up the digitial represenatation of the data are not precisely 1/3. On my particular platform (JVM 1.6 Windows 64 bit), it's 1.0, but it might not be on yours.

Upvotes: 2

Bathsheba
Bathsheba

Reputation: 234635

Due to the way that floating point variables are represented, not all numbers can be represented precisely. In fact, very few can.

When you write

float f1 = (float) 3.2;

and compare that with 3.2, you are comparing f1 (a float) with 3.2 (a double: 3.2 entered as a literal is implicitly a double type). In your statement f1 == 3.2, f1 gets implicitly converted to a double, but by then, precision has been lost. This is because 3.2 is one of those numbers that cannot be represented precisely and double makes a better job of it than float.

Coincidentally, 6.5 is one of those numbers (double or float) that can be expressed precisely due to the internal scheme that Java uses to represent floating point. That's why, in your case, f2 == 6.5 is true.

Upvotes: 3

Thirumalai Parthasarathi
Thirumalai Parthasarathi

Reputation: 4671

use a cast if (f1 == (float)3.2) { then it will work.

literals like 3.2 are of type double and you are comparing a float with a double, and it causes such things to happen.

As @JNL pointed out

This issue occurs because decimal values cannot be represented accurately in the binary.

Upvotes: 2

Jim
Jim

Reputation: 1066

Although it may not seem correct, when you run

float f1 = (float) 3.2;

f1 is not really equal to 3.2. As mentioned, there are several ways to work around this issue.

Upvotes: 1

Surveon
Surveon

Reputation: 723

I'm going to try my hand at a technical explanation for this. Since these values are being ultimately stored in the binary format, under some conditions precision will be lost.

6.5 should not lose any precision, as it can be converted to the binary value 110.1.

3.2, however, cannot be converted cleanly like this because the binary representation of .2 becomes irrational. It would be something along the lines of 11.00110011... This can only be, at best, rounded to 3.2 when converted the other way.

If somebody could verify what I'm saying, it would be fantastic - this is is based on an admittedly limited knowledge of how Java is handling this.

Upvotes: 5

JNL
JNL

Reputation: 4703

There are many ways to get around this issue,

This issue occurs because decimal values cannot be represented accurately in the binary.

  1. Have a tolerance value and check if the difference is less than the tolerance value.
  2. Multiply it by 10/100/... and then compare the numbers
  3. Look into BigDecimal.

And go through this for sure.

Upvotes: 2

Related Questions