Floating point accuracy
public class MaxValueComparisonTest {
static double d;
static float f;
public static void main(String args[]) {
compare(Long.MAX_VALUE, Long.MAX_VALUE );
compare(Integer.MAX_VALUE, Integer.MAX_VALUE ); //1
compare(Character.MAX_VALUE, Character.MAX_VALUE); //2
compare(Short.MAX_VALUE, Short.MAX_VALUE ); //3
compare(Byte.MAX_VALUE, Byte.MAX_VALUE ); //4
}
static void compare(double d, float f) {
if (f == d) System.out.print(" equal" );
else System.out.print(" unequal");
}
}
Question: Please explain the output
To understand this result you have to understand the concept of floating point precision. The primitive type float can represent 23 bits of precision. Now, Integer.MAX_VALUE needs 32 bits of precision to represent its exact value. so Integer.MAX_VALUE is unable to fit into 23 bits precision of float. So it is truncated to 23 bits in the case of Float and not truncated in double. That’s why the result is false. The conversion to float rounds, the conversion to double does not.
The only question is why Long.MAX_VALUE doesn't have the same behavior ?
When it comes to Long.MAX_VALUE, primitive type long needs 64 bits of precision to represent its exact value. The primitive type double can represent 52 bits of precision and float can represent only 23 bits of precision. Hence Long.MAX_VALUE rounds in both cases.
In the above code, you're comparing a float and a double, so the compiler promotes the float to a double in order to do the comparison, because the compiler needs the two values to be the same type before comparing them.
Example to prove the above theory:
public class FloatNDouble{
public static void main(String args[]) {
System.out.println(Long.toBinaryString(Double.doubleToLongBits((double)(float)Integer.MAX_VALUE)));
System.out.println(Long.toBinaryString(Double.doubleToLongBits((double)Integer.MAX_VALUE)));
System.out.println(Long.toBinaryString(Double.doubleToLongBits((double)(float)Long.MAX_VALUE)));
System.out.println(Long.toBinaryString(Double.doubleToLongBits((double)Long.MAX_VALUE)));
}
}
Notice that to compare the two numbers the float will have to be converted to a double. That's why I did (double)(float)Integer.MAX_VALUE and (double)(float)Long.MAX_VALUE.
Output:
100000111100000000000000000000000000000000000000000000000000000
100000111011111111111111111111111111111110000000000000000000000
100001111100000000000000000000000000000000000000000000000000000
100001111100000000000000000000000000000000000000000000000000000 Do not confuse the precision of a floating point number with its range. Both float and double can represent an int (or) long within their respective ranges. That's why we get widening conversions from int (or) long to float or double.
1 Comments:
5 Riveting Soldier Blogs
One of the main ways in which the current war differs from its predecessors is the direct access that soldiers have to those at home via online blogs.
This is truly a great blog! I will bookmark you..
I have a work from home site. It pretty much covers work from home related stuff.
Come and check it out if you get time :-)
Post a Comment
<< Home