简体   繁体   中英

Java: Adding 2 float numbers and get the result as double

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?

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 (eg, with System.out.printf() or String.format() ).

You should also read What Every Computer Scientist Should Know About Floating-Point Arithmetic .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM