Java double precision

Discussion in 'Java' started by info, Dec 7, 2004.

  1. info

    info Guest

    I know the following behaviour is an old problem,
    but still I don't understand why such a simple piece of code:


    double val = 0;
    for(int i=0;i<10;i++) {
    val+=0.1;
    System.out.println(val);
    }

    has the following (terrible) output:

    0.1
    0.2
    0.30000000000000004
    0.4
    0.5
    0.6
    0.7
    0.7999999999999999
    0.8999999999999999
    0.9999999999999999


    ???

    Why, as a developer, I have to use a trick like this to solve the
    problem:

    java.text.DecimalFormat df = new
    java.text.DecimalFormat("###.########");
    double val = 0;
    for(int i=0;i<10;i++) {
    val+=0.1;
    val = df.parse(df.format(val)).doubleValue();
    System.out.println(val);
    }


    Thank you in advance
    Vincenzo Caselli

    http://www.censnet.it
     
    info, Dec 7, 2004
    #1
    1. Advertisements

  2. Because double and float are internally represented as *binary* fractions
    according to the IEEE standard 754
    and can therefore not represent decimal fractions exactly.
    http://mindprod.com/jgloss/floatingpoint.html
    http://www.math.byu.edu/~schow/work/IEEEFloatingPoint.htm
    *groan* You're 95% there and yet took the TOTALLY wrong turn at the last
    intersection. You want to *format* numbers, so why are you using
    DecimalFormat.parse()??? What do you think the format() method is for?

    Furthermore, if you really need exact representation of decimal fractions
    (usually the case only for financial applications), use java.math.BigDecimal.
     
    Michael Borgwardt, Dec 7, 2004
    #2
    1. Advertisements

  3. info

    wald Guest

    wald, Dec 7, 2004
    #3
  4. There are two incompatible objectives for string conversion
    of floating point data:

    1. Produce a tidy result showing only meaningful digits.

    2. Produce a result that uniquely identifies the floating
    point number.

    Language and library developers pick one for the default
    conversion. In C, for example, printf aims for #1,
    defaulting to 6 digit precision.

    Java uses #2 as the default, producing enough digits to
    ensure that the reverse conversion will recover the double.
    The result of adding 0.1+0.1+0.1 really is different
    from 0.3.

    I don't fully understand the reason for your "trick". I
    would have used the DecimalFormat when aiming for tidy
    output, but would not have converted back or used the
    result in continuing calculations. Doing so throws away
    precision if the mathematical answer is not a short decimal
    fraction. For example, try substituting 1/3.0 for 0.1 in
    your test.

    If you are only concerned with exact representation of short
    decimal fractions, and don't need to deal with numbers like
    1/3.0, consider using BigDecimal instead of double. Any
    number that would be improved by your trick can be exactly
    represented as a BigDecimal with scale=8.

    Patricia
     
    Patricia Shanahan, Dec 8, 2004
    #4
  5. info

    Chris Smith Guest

    It's because you're thinking in decimal, but the computer thinks in
    binary. 0.1 is a repeating decimal number in binary. To understand
    this case, we could take an analogous algorithm in decimal; say, adding
    1/3 instead of 1/10. In this example, we'll give the numbers ten
    significant digits of precision, so:

    0.3333333333
    + 0.3333333333
    ------------
    = 0.6666666666
    + 0.3333333333
    ------------
    = 0.9999999999

    So the same thing happens with repeating decimal numbers in base 10 as
    well. The cumulative error from adding 0.3333333333 instead of exactly
    1/3 adds up. It's only counterintuitive because you're not expecting
    0.1 to be a repeating decimal, and that's because you're not thinking in
    base 2 like the computer is.
    No, you can write:

    DecimalFormat df = new DecimalFormat("###.########");
    double val = 0;
    for (int i = 0; i < 10; i++)
    {
    val += 0.1;
    System.out.println(df.format(val));
    }

    As Patricia said, you're assuming that the "correct" answer is achieved
    by truncating the result in decimal that then parsing it back again.
    Only in the very limited case of nice round numbers is that true. This
    would be a very poor idea if you were working with any kind of measured
    or calculated quantity. You shouldn't be assuming enough precision that
    rounding error will matter anyway, so there's no need to make that round
    trip.

    --
    www.designacourse.com
    The Easiest Way To Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
     
    Chris Smith, Dec 10, 2004
    #5
  6. info

    soft

    Joined:
    Jun 10, 2009
    Messages:
    1
    Likes Received:
    0
    Hello, First of all, sorry for my ignorance. I have the following two questions:
    1. Have the results showing in the program below anything to do with this discussion? I mean, is it the same problem?
    2. Does my friend need to worry about this issue, if she is writing a program for a bank? :flute:

    Can anyone explain what is happening below?


    for(int i=0;i<20;i++)
    System.out.println(i*1.26);

    -----
    0.0
    1.26
    2.52
    3.7800000000000002
    5.04
    6.3
    7.5600000000000005
    8.82
    10.08
    11.34
    12.6
    13.86
    15.120000000000001
    16.38
    17.64
    18.9
    20.16
    21.42
    22.68
    23.94
     
    soft, Jun 10, 2009
    #6
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.