0

As I know double numbers reserve 64-bit in memory. Float numbers reserve 32-bit.

I tried the following:

double result=0.1f+0.3f;
System.out.println(result);

And as a result it prints 0.4000000059604645. Is the data from the next memory block (32 first bits and the next 32)?
Is it something else?

LiTTle
  • 1,811
  • 1
  • 20
  • 37

1 Answers1

8

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.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • 0.4 does not have an exact base 2 representation. In lowest terms, it is 2/5, and 5 is not a factor any power of two. The actual double bit pattern is 0x3fd999999999999a, equivalent to 0.40000000000000002220446049250313080847263336181640625. All that the final "true" means is that the value of ddd is the closest double to decimal 0.4. – Patricia Shanahan Jul 12 '13 at 19:17
  • @PatriciaShanahan - Good catch. I don't know what I was thinking. I rephrased that part of the answer. It's interesting, though, that 10*(0.4d) == 4 (exactly). – Ted Hopp Jul 12 '13 at 19:41
  • Sometimes, the rounding error on one calculation cancels out the rounding error on a previous calculation, leading to an exact result. That is what is happening on the 10*(0.4d) calculation. – Patricia Shanahan Jul 12 '13 at 20:39