2

I was running this code and the loop didn't seem to stop at the specified condition.

for(double i=1.0; i!=2.0; i+=0.2){
    System.out.println("The value of i :" +i);
}

Is this a problem with the way the double number is represented in Java?

cowls
  • 24,013
  • 8
  • 48
  • 78
Ankur Sharma
  • 283
  • 2
  • 13
  • 1
    `Is this a problem with the way the double number is represented in Java?` To be exact, the bninary representation of floating point numbers is the cause. This is something you should solve by acting clever: `for(double i=1.0; i<=2.0; i+=0.2){` Even though [my answer here](http://stackoverflow.com/a/13513206/1667004) is for C, it is the same pie for Java too... – ppeterka Mar 07 '13 at 14:17

2 Answers2

7

This is a fairly common problem: 0.2 cannot be represented exactly in a double, so 2.0 is not equal to the sum of ten 0.2 added together. You need to use < instead of != to stop the loop.

Note that your loop would have worked for an increment which is equal to a negative power of 2, say, 0.25: the loop below works fine, and stops as expected:

for(double i=1.0; i!=2.0; i+=0.25){
    System.out.println("The value of i :" +i);
}

This works, because 0.25 can be represented exactly in a double. This little experiment shows that you need to be extremely cautious when comparing doubles for equality or inequality.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Actully the last value before 2 is approximately 1.999 . . . and the next value is something like 2.1999 . . . and so it will never be 2.0. Is it best to avoid comparison using floating point numbers? – Ankur Sharma Mar 07 '13 at 14:21
  • 1
    like dasblinkenlight said, use < or > instead of a direct comparison. that's generally a good idea for loops anyway – Jeff Hawthorne Mar 07 '13 at 14:22
  • @JeffHawthorne I wouldn't necessarily generalize it to loops with conditions based on integers: an argument in favor of using `!=` there is that the post-condition of such a loop is stronger, making formal analysis of your program easier. – Sergey Kalinichenko Mar 07 '13 at 14:24
2

Yes that's it - 0.2 can't be exactly represented as a double. To see the exact values, you can run the following program:

public static void main(String[] args) {
    for (double i = 1.0; i != 2.0 && i < 3.0; i += 0.2) {
        System.out.println("The value of i :" + new BigDecimal(i));
    }
}

which prints:

The value of i :1
The value of i :1.1999999999999999555910790149937383830547332763671875
The value of i :1.399999999999999911182158029987476766109466552734375
The value of i :1.5999999999999998667732370449812151491641998291015625
The value of i :1.79999999999999982236431605997495353221893310546875
The value of i :1.9999999999999997779553950749686919152736663818359375
The value of i :2.199999999999999733546474089962430298328399658203125
The value of i :2.399999999999999911182158029987476766109466552734375
The value of i :2.600000000000000088817841970012523233890533447265625
The value of i :2.800000000000000266453525910037569701671600341796875

Your options:

  • round the numbers
  • use a i < 2.0 condition (but you might miss one iteration depending on rounding)
  • use a BigDecimal for an exact representation of 0.2
assylias
  • 321,522
  • 82
  • 660
  • 783