Reputation: 1926
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
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
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
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
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
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
Reputation: 4703
There are many ways to get around this issue,
This issue occurs because decimal values cannot be represented accurately in the binary.
- Have a tolerance value and check if the difference is less than the tolerance value.
- Multiply it by 10/100/... and then compare the numbers
- Look into BigDecimal.
And go through this for sure.
Upvotes: 2