This line:
double result=0.1f+0.3f;
first converts the strings "0.1" and "0.3" to float
values, then adds the two float
values using the rules for float
, and then finally converts the result to a double
to do the assignment. The conversion of the float literals to float
values introduces rounding error. (Just like 1/3 has an infinite, repeating expansion in base 10, 1/10 and 3/10 have infinite, repeating expansions in base 2, and cannot be represented exactly in either float
or double
.) The float
addition may introduce a bit more error (pun intended). The widening expansion from float
to double
is exact, but the system then assumes that the expanded resolution contains meaningful data.
If you want the addition to be done using the rules for double
, then you need to convert at least one of the operands to double
first, either with a cast or by using a double
literal:
double result=0.1f+0.3d;
In the above, 0.3 will be converted to a double
to full double
precision; 0.1 will be converted to a float
and then widened to a double
, resulting in a double
value that has more rounding error than would 0.1d
. Most compilers would do this at compile time.
Compiling this code with Oracle's javac compiler (version 1.7.0_11, default settings):
public class Foo1 {
public static void main(String[] args) {
double dff = 0.1f + 0.3f;
double dfd = 0.1f + 0.3d;
double ddd = 0.1d + 0.3d;
System.out.println("dff=" + dff);
System.out.println("dfd=" + dfd);
System.out.println("ddd=" + ddd);
System.out.println("dff==dfd: " + (dff == dfd));
System.out.println("dff==ddd: " + (dff == ddd));
System.out.println("dfd==ddd: " + (dfd == ddd));
System.out.println("ddd==0.4: " + (10*ddd == 4));
}
}
produces bytecode that starts like this (using javap -c to disassemble):
ldc2_w #2 // double 0.4000000059604645d
dstore_1
ldc2_w #4 // double 0.4000000014901161d
dstore_3
ldc2_w #6 // double 0.4d
dstore 5
and produces this output:
dff=0.4000000059604645
dfd=0.4000000014901161
ddd=0.4
dff==dfd: false
dff==ddd: false
dfd==ddd: false
ddd==0.4: true
The last line shows "true" because the representation errors of 0.1d and 0.3d and the rounding error of the addition (if any) happen to combine in a way that exactly matches the representation error of 0.4d. Things would not be so nice if you changed 0.3
to 0.2
(and changed 10*ddd==4
to 10*ddd==3
).
In general, regardless of whether you use float
or double
, there is going to be some rounding error and the results are unlikely to be exact. For extended precision, you should use BigDecimal
. If you just need clean-looking output, use a format specifier (e.g., with System.out.printf()
or String.format()
).
You should also read What Every Computer Scientist Should Know About Floating-Point Arithmetic.