Double increments in Java

25,398

Solution 1

Welcome to the world of floating point, where 0.1 isn't 0.1. The problem is that many numbers, including 0.1, cannot be represented exactly in a double. So you aren't really adding exactly 0.1 to x each time through the loop.

One approach is to use integer arithmetic and divide by 10:

int i = 0;
while (i <= 10) {
    double x = i / 10.0;
    . . .
    i++;
}

Another approach is to make x a BigDecimal, where you can specify that you want a particular precision. It basically is doing what the above loop does (an integer plus a scale), but packaged up in a nice class with lots of bells and whistles. Oh, and it has arbitrary precision.

Solution 2

you need to use the decimal formatter to get the expected output.

Below is the code for generating the expected output:

import java.text.DecimalFormat;


public class FloatIncrement {

    public static void main (String args[]){

        double x= 0.0;
        DecimalFormat form = new DecimalFormat("#.#");      
        while(x<0.9){
            x= x+0.1;
            System.out.println("X : "+Double.valueOf(form.format(x)));          

        }

    }
}

Solution 3

To get output you want, you could use DecimalFormat. Here is some sample code.

import java.text.DecimalFormat;

public class DF {

  public static void main(String [] args) {

    double x = 0.1;
    DecimalFormat form = new DecimalFormat("#.#");
    while (x <= .9) {
      System.out.println(Double.valueOf(form.format(x)));
      x += 0.1;
    }

  }

}

As far as the implementation you have now, there is no guarantee as to the precision of what gets printed due to the nature of floating point numbers.

Solution 4

Using BigDecimal

double x = 0.0;
   int decimalPlaces = 2;           

  while ( x<=1 )
  {

    x += 0.1;
    BigDecimal bd = new BigDecimal(x);
    bd = bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
    x = bd.doubleValue();           

    System.out.println(x); 
  }
Share:
25,398
user1483799
Author by

user1483799

Updated on October 22, 2020

Comments

  • user1483799
    user1483799 over 3 years

    Possible Duplicate:
    How to iterate between 0.1f and 1.0f with 0.1f increments in Java?

    Part of my program needs to use values inside a while loop as:

    0.1

    0.2

    0.3

    ...

    0.9

    so I need to provide them inside that loop. Here is the code:

    double x = 0.0;
    while ( x<=1 )
    {
    // increment x by 0.1 for each iteration
    x += 0.1;
    }
    

    I need the output to be EXACTLY:

    0.1

    0.2

    0.3

    0.4

    0.5

    0.6

    0.7

    0.8

    0.9

    But it actually gives me something like:

    0.1

    0.2

    0.300000000000000000000000004

    0.4

    0.5

    0.6

    0.79999999999999999999999999

    0.89999999999999999999999999

    0.99999999999999999999999999

    • Mukus
      Mukus over 11 years
      You seem to be adding the right number. I don't see why this would not work.
    • cHao
      cHao over 11 years
      @TejaswiRana: It doesn't work because 0.1 is actually something like 0.0999999999999999999999 or 0.10000000000000000001. Decimal fractions can't be losslessly represented by a double.
  • Mukus
    Mukus over 11 years
    Really? When you add 0.1 you are not actually adding 0.1? That can throw off a lot of calculations in a lot of applications that exist till date.
  • cHao
    cHao over 11 years
    @TejaswiRana: Yep. That's why double is only a good idea for calculations that can tolerate the rounding error. Game physics calculations? Sure. Money? Hell no. Basically if the number is a measurement, doubles are generally ok; if it's a count, use a BigDecimal or integers instead.
  • Ted Hopp
    Ted Hopp over 11 years
    The opening sentence is a bit misleading. Every double is a rational value; the issue is the converse: not every rational value is a double value.
  • Shariq
    Shariq over 11 years
    You could also round to one significant figure using the code available here. stackoverflow.com/questions/202302/…
  • Mukus
    Mukus over 11 years
    So then if I were creating a banking app, what would I use as data type? Float?
  • Mukus
    Mukus over 11 years
    @cHao I take it that this is the same for C# too?
  • Ted Hopp
    Ted Hopp over 11 years
    @TejaswiRana - A lot of applications that use double are written using tolerances to compensate for this. For those that are not written that way, either the roundoff errors are not important or the applications are buggy. Alternative approaches include all-integer arithmetic, arbitrary precision packages (which are basically all-integer arithmetic at their core), or rational arithmetic packages (likewise integer-based).
  • cHao
    cHao over 11 years
    @TejaswiRana: Floats are even worse than doubles as far as rounding error is concerned. For a banking app, you'd probably do best to have a certain number of decimal digits you want to keep, and multiply your amounts so that you can turn them into ints or longs.
  • Shariq
    Shariq over 11 years
    @TedHopp - changed my answer; you're right. I didn't explain what I meant by rational - I meant in memory, the number isn't represented as a ratio of a numerator to a denominator.
  • cHao
    cHao over 11 years
    @TejaswiRana: Yep. Same for most languages that support floating point numbers. C#, PHP, Java, C, C++, VB, etc.
  • Mukus
    Mukus over 11 years
    stackoverflow.com/questions/2863388/… It gets even worse in C#
  • cHao
    cHao over 11 years
    @TejaswiRana: Not so much, actually. .net has a Decimal type, which is a decimal floating-point number (rather than the binary ones the CPU probably supports). 0.1 can be accurately and losslessly represented by a C# decimal (though it looks like 0.1m or somethig like that in C#), so it's safe to use for money. Drawback is, a lot of operations (logs, non-integer exponentiation, basically anything that'd typically yield an irrational result) isn't supported for them without the help of third-party libs.
  • user207421
    user207421 over 11 years
    @cHao For a banking or accounting application it would be tantamount to criminal incompetence to use floating point at all. I've seen contractors hauled over the coals for it and required to remedy at their own expense.
  • squiguy
    squiguy over 11 years
    That is some good looking code :)
  • cHao
    cHao over 11 years
    @EJP: There's a bit of difference with C#'s decimal floating-point, though. A decimalcan accurately hold around 30 significant digits. That's enough for even a trillionth of a penny on amounts in the trillions.
  • simbu94
    simbu94 over 11 years
    @squiguy thank you for your suggestion
  • Ivan Balashov
    Ivan Balashov almost 4 years
    The error is accumulated in this example. Better to reduce number of floating point operations if you can (not relevant to this case, but matters if your loops goes to a large number).