7

This code isn't working as I thought it would.

a=-1;   
b=0.1;   
for(i=0;i<=20;i++){  
    System.out.println(i + ". x= " + a);   
    a=a+b;   
}       

On the console I should see:

0. x= -1.0  
1. x= -0.9  
2. x= -0.8  
3. x= -0.7  
4. x= -0.6  
5. x= -0.5  
6. x= -0.4  
7. x= -0.3  

...etc

But this is what happens:

0. x= -1.0  
1. x= -0.9  
2. x= -0.8  
3. x= -0.7000000000000001  
4. x= -0.6000000000000001  
5. x= -0.5000000000000001  
6. x= -0.40000000000000013  
7. x= -0.30000000000000016  
8. x= -0.20000000000000015  
9. x= -0.10000000000000014  
10. x= -1.3877787807814457E-16  
11. x= 0.09999999999999987  
12. x= 0.19999999999999987  
13. x= 0.2999999999999999  
14. x= 0.3999999999999999  
15. x= 0.4999999999999999  
16. x= 0.5999999999999999  
17. x= 0.6999999999999998  
18. x= 0.7999999999999998  
19. x= 0.8999999999999998  
20. x= 0.9999999999999998  

What am I doing wrong here?

David Brossard
  • 13,584
  • 6
  • 55
  • 88

6 Answers6

4

What you have here is floating point inaccuracy. Because doubles have limited precision they cannot precisely represent all decimal numbers. In particular 0.1 is a recurring binary so all finite length binary representations will be inaccurate. This means the computer cannot store the numbers you're using exactly.

You can fix your output by formatting it (e.g. System.out.format("%d. x=%.1f", i, a);) or you can fix your numbers by using BigDecimal instead of double. Alternatively you could reduce the scale of the problem by calculating a each time rather than accumulating (and adding an incremental error each time), e.g. a = i/10.0. It depends on what you are trying to achieve.

The important "take home message" is that doubles cannot be relied on to give complete accurate answers and you should expect small errors in floating point arithmetic.

Jack Aidley
  • 19,439
  • 7
  • 43
  • 70
2

When you need precision: use BigDecimal instead of double.

Refer to this question for more details: Double vs. BigDecimal?

edit: if you don't need precision; you're ok with formatting the output..

Community
  • 1
  • 1
ljgw
  • 2,751
  • 1
  • 20
  • 39
  • 10
    No. He just needs to format his output. These aren't financial or rocket engineering equations, but simple floating point calculations. Using a double with formatted output will do just fine. – Hovercraft Full Of Eels Dec 02 '13 at 14:13
  • @HovercraftFullOfEels: How do we know? Our asker doesn't tell us what the downstream application of this is. – Jack Aidley Dec 02 '13 at 14:21
2

Try formatting your output:

for(i=0;i<=20;i++){  
    System.out.format("%d. x=%.1f", i, a);   
    a=a+b;   
}  

For more on formatting output, see the docs

Eric Wilson
  • 57,719
  • 77
  • 200
  • 270
1

A personal favorite of mine is to use System.out.printf()
Like it's C counterpart you define the type of the variables your going to pass to it then just fling it an something of that type. For example System.out.printf("%.1f", yourDouble);

Should do the trick.

Resources: Printf cheat sheet

Community
  • 1
  • 1
daark
  • 326
  • 3
  • 10
0

You are probably using ints for each of those objects. Instead when you go to display them call this method first :

public static double round(double value, int places) {
    if (places < 0) throw new IllegalArgumentException();

    BigDecimal bd = new BigDecimal(value);
    bd = bd.setScale(places, BigDecimal.ROUND_HALF_UP);
    return bd.doubleValue();
}

Or use the correct type of object instead of ints...

RenegadeAndy
  • 5,440
  • 18
  • 70
  • 130
0

use String.format or just pain decimal formatting syntax in system.out.println and you should see what you want. float point arithmetic is internally represented in a different way. So a simple print of such values wont always give you want you need interms of on screen view format.

Nazgul
  • 1,892
  • 1
  • 11
  • 15