Java Double trouble

CODE:

public class Test {

    public static void main(String[] args) {

       	System.out.println("Exponent loop:");
	       for(int i=1; i<10; ++i)
		       System.out.println(Math.pow(0.1, i));
	
	    System.out.println("\nMultiplication loop:");
	    double a = 1;
	    for(int i=1; i<10; ++i){
		    a *= 0.1;
		    System.out.println(a);
	    }
    }
}

OUTPUT:

Exponent loop:
0.1
0.010000000000000002 
0.0010000000000000002
1.0000000000000002E-4
1.0000000000000003E-5
1.0000000000000004E-6
1.0000000000000004E-7
1.0000000000000004E-8
1.0000000000000005E-9

Multiplication loop:
0.1
0.010000000000000002
0.0010000000000000002
1.0000000000000003E-4
1.0000000000000004E-5
1.0000000000000004E-6
1.0000000000000005E-7
1.0000000000000005E-8
1.0000000000000005E-9

WHY ??

First of all, I like your question title. “Double trouble”. Very creative :slight_smile:

Anyways, to answer your question, floating-point arithmetic is almost never exact in any programming language. Read this article to find out more information: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

One way Java programmers solve this is by using the BigDecimal class. Here’s the javadoc for that

http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html

Briefly, to multiply two BigDecimals, you would do:

BigDecimal d1 = new BigDecimal( "0.22132" ); // I chose 0.22132 arbitrarily. 
BigDecimal d2 = new BigDecimal( "0.123" ); // I chose 0.123 arbitrarily too.
System.out.println( d1.multiply(d2) );

The output would be 0.02722236 (I checked with my calculator. This is the correct answer).

Now, if you did this with doubles like this,

System.out.println( 0.22132 * 0.123 );

You’d get 0.027222359999999998

One other way of solving this sort of problem (it won’t work here though) is to just cast the double as you’re printing it out. So, your output statements would be

System.out.println( (int)(a) );
System.out.println( (int)(Math.pow(0.1,i));

It won’t work here though since casting just truncates the decimal values. So, if you did casting, all your outputs would be 0. However, if this problem shows up again, casting might be a solution.

But, for this particular problem, BigDecimal is your way to go.

1 Like

Thanks a lot @kullalok… I thought BigDecimal was only used to store a number with a lot of decimal places… From now on I will be more careful with problems that require the use of double variables…

@junior94 on the other hand, problem setters know about this problem, so typically you will see something like “print the result with error less than 10^-6”, so if you print 0.027222359999999998 instead of 0.02722236 it’s ok :wink: Also be careful, that BigDecimal is a lot slower, so instead of WA you will get TLE probably. There is just one problem you need to hanlde with doubles - you cannot use x == y test, but you have to use something like x in (y-e, y+e) whre e is let say 10^-7…

1 Like