Java rounding with big Decimal.

Discussion in 'Java' started by ChrisMM, Jun 10, 2004.

  1. ChrisMM

    ChrisMM Guest

    I have a double that I need to round to 6 dp, I thought I could just
    assign it to a BigDecimal, call its scale method and assign the result
    back to the double variable but something weird happens :-
    This code ...

    double db = 0.1234567890;

    System.out.print(" Double = "+ db );
    BigDecimal big = new BigDecimal( db );
    System.out.print(" big = "+big);
    System.out.print(" rounded big = "+big.setScale (6,
    BigDecimal.ROUND_HALF_UP));
    System.out.println(" back to double = " + new Double(
    big.doubleValue() ));

    produces this output...

    Double = 0.12345678900000004
    big = 0.1234567890000000389694179148136754520237445831298828125
    rounded big = 0.123457
    back to double = 0.12345678900000004

    The double somehow goes back to its original value ???
    Whats happening ? and how do I get the double to be the rounded
    amount.

    Cheers,

    ChrisMM
    ChrisMM, Jun 10, 2004
    #1
    1. Advertising

  2. ChrisMM

    Andy Fish Guest

    the SetScale method does not update the value returned, it returns another
    bigdecimal value rounded off.

    you need something like:

    System.out.println(" back to double = " + new Double( big.setScale (6,
    BigDecimal.ROUND_HALF_UP).doubleValue() ));



    "ChrisMM" <> wrote in message
    news:...
    > I have a double that I need to round to 6 dp, I thought I could just
    > assign it to a BigDecimal, call its scale method and assign the result
    > back to the double variable but something weird happens :-
    > This code ...
    >
    > double db = 0.1234567890;
    >
    > System.out.print(" Double = "+ db );
    > BigDecimal big = new BigDecimal( db );
    > System.out.print(" big = "+big);
    > System.out.print(" rounded big = "+big.setScale (6,
    > BigDecimal.ROUND_HALF_UP));
    > System.out.println(" back to double = " + new Double(
    > big.doubleValue() ));
    >
    > produces this output...
    >
    > Double = 0.12345678900000004
    > big = 0.1234567890000000389694179148136754520237445831298828125
    > rounded big = 0.123457
    > back to double = 0.12345678900000004
    >
    > The double somehow goes back to its original value ???
    > Whats happening ? and how do I get the double to be the rounded
    > amount.
    >
    > Cheers,
    >
    > ChrisMM
    Andy Fish, Jun 10, 2004
    #2
    1. Advertising

  3. ChrisMM

    Dave Monroe Guest

    (ChrisMM) wrote in message news:<>...
    > I have a double that I need to round to 6 dp, I thought I could just
    > assign it to a BigDecimal, call its scale method and assign the result
    > back to the double variable but something weird happens :-
    > This code ...
    >
    > double db = 0.1234567890;
    >
    > System.out.print(" Double = "+ db );
    > BigDecimal big = new BigDecimal( db );
    > System.out.print(" big = "+big);
    > System.out.print(" rounded big = "+big.setScale (6,
    > BigDecimal.ROUND_HALF_UP));
    > System.out.println(" back to double = " + new Double(
    > big.doubleValue() ));
    >
    > produces this output...
    >
    > Double = 0.12345678900000004
    > big = 0.1234567890000000389694179148136754520237445831298828125
    > rounded big = 0.123457
    > back to double = 0.12345678900000004
    >
    > The double somehow goes back to its original value ???
    > Whats happening ? and how do I get the double to be the rounded
    > amount.
    >
    > Cheers,
    >
    > ChrisMM


    Check out DecimalFormat.
    Dave Monroe, Jun 11, 2004
    #3
  4. (ChrisMM) wrote:
    > I have a double that I need to round to 6 dp, I thought I could just
    > assign it to a BigDecimal, call its scale method and assign the result
    > back to the double variable but something weird happens :-
    > This code ...
    >
    > double db = 0.1234567890;
    >
    > System.out.print(" Double = "+ db );
    > BigDecimal big = new BigDecimal( db );
    > System.out.print(" big = "+big);
    > System.out.print(" rounded big = "+big.setScale (6,
    > BigDecimal.ROUND_HALF_UP));
    > System.out.println(" back to double = " + new Double(
    > big.doubleValue() ));
    >
    > produces this output...
    >
    > Double = 0.12345678900000004
    > big = 0.1234567890000000389694179148136754520237445831298828125
    > rounded big = 0.123457
    > back to double = 0.12345678900000004
    >
    > The double somehow goes back to its original value ???
    > Whats happening ? and how do I get the double to be the rounded
    > amount.


    What you have to remember is that the double type is inherently
    inaccurate... You say it goes back to its original value, but
    it doesn't -- it goes back to 0.12345678900000004. The original
    value was 0.1234567890. See, the double var already accrued a
    bit of error -- 0.00000000000000004 to be exact.

    Now, IIRC, the BigDecimal var still holds the original value,
    which is 0.12345678900000004, because you didn't do:

    big = big.setScale (6, BigDecimal.ROUND_HALF_UP));

    If you do that, I think you'll find that your final result is
    now about 0.123457, though possibly with some error. Hopefully
    someone will correct me if I'm wrong though.

    But generally speaking, get rid of the doubles if you need
    the accuracy. It's a lot clumsier to use, but it's ACCURATE.
    Doubles suck. :)
    --
    //*================================================================++
    || Russ Perry Jr 2175 S Tonne Dr #114 Arlington Hts IL 60005 ||
    || 847-952-9729 [NEW!] VIDEOGAME COLLECTOR! ||
    ++================================================================*//
    Russ Perry Jr, Jun 12, 2004
    #4
  5. ChrisMM

    Liz Guest

    Sounds like a lot of hastle just to do rounding. In the
    old days of 'basic' we used to just multiply and divide
    like this.

    b = int((a*100+5)/100); for two decimal places


    "Russ Perry Jr" <> wrote in message
    news:...
    > (ChrisMM) wrote:
    > > I have a double that I need to round to 6 dp, I thought I could just
    > > assign it to a BigDecimal, call its scale method and assign the result
    > > back to the double variable but something weird happens :-
    > > This code ...
    > >
    > > double db = 0.1234567890;
    > >
    > > System.out.print(" Double = "+ db );
    > > BigDecimal big = new BigDecimal( db );
    > > System.out.print(" big = "+big);
    > > System.out.print(" rounded big = "+big.setScale (6,
    > > BigDecimal.ROUND_HALF_UP));
    > > System.out.println(" back to double = " + new Double(
    > > big.doubleValue() ));
    > >
    > > produces this output...
    > >
    > > Double = 0.12345678900000004
    > > big = 0.1234567890000000389694179148136754520237445831298828125
    > > rounded big = 0.123457
    > > back to double = 0.12345678900000004
    > >
    > > The double somehow goes back to its original value ???
    > > Whats happening ? and how do I get the double to be the rounded
    > > amount.

    >
    > What you have to remember is that the double type is inherently
    > inaccurate... You say it goes back to its original value, but
    > it doesn't -- it goes back to 0.12345678900000004. The original
    > value was 0.1234567890. See, the double var already accrued a
    > bit of error -- 0.00000000000000004 to be exact.
    >
    > Now, IIRC, the BigDecimal var still holds the original value,
    > which is 0.12345678900000004, because you didn't do:
    >
    > big = big.setScale (6, BigDecimal.ROUND_HALF_UP));
    >
    > If you do that, I think you'll find that your final result is
    > now about 0.123457, though possibly with some error. Hopefully
    > someone will correct me if I'm wrong though.
    >
    > But generally speaking, get rid of the doubles if you need
    > the accuracy. It's a lot clumsier to use, but it's ACCURATE.
    > Doubles suck. :)
    > --
    > //*================================================================++
    > || Russ Perry Jr 2175 S Tonne Dr #114 Arlington Hts IL 60005 ||
    > || 847-952-9729 [NEW!] VIDEOGAME COLLECTOR! ||
    > ++================================================================*//
    Liz, Jun 12, 2004
    #5
  6. "Liz" <> wrote:
    > Sounds like a lot of hastle just to do rounding. In the
    > old days of 'basic' we used to just multiply and divide
    > like this.
    >
    > b = int((a*100+5)/100); for two decimal places


    That's not that much better than just doing:

    big = big.setScale (2, BigDecimal.ROUND_HALF_UP));

    ....plus you have other rounding options if you need them.

    Besides, even what you posted WORKS in Java, it's just that
    you are STILL stuck with inaccuracy. So again, you're still
    better off using BigDecimal from the beginning rather than
    doubles, despite the extra code. But, YMMV.

    > "Russ Perry Jr" <> wrote:
    > > (ChrisMM) wrote:
    > > > I have a double that I need to round to 6 dp, I thought I could just
    > > > assign it to a BigDecimal, call its scale method and assign the result
    > > > back to the double variable but something weird happens :-
    > > > This code ...
    > > >
    > > > double db = 0.1234567890;
    > > >
    > > > System.out.print(" Double = "+ db );
    > > > BigDecimal big = new BigDecimal( db );
    > > > System.out.print(" big = "+big);
    > > > System.out.print(" rounded big = "+big.setScale (6,
    > > > BigDecimal.ROUND_HALF_UP));
    > > > System.out.println(" back to double = " + new Double(
    > > > big.doubleValue() ));
    > > >
    > > > produces this output...
    > > >
    > > > Double = 0.12345678900000004
    > > > big = 0.1234567890000000389694179148136754520237445831298828125
    > > > rounded big = 0.123457
    > > > back to double = 0.12345678900000004
    > > >
    > > > The double somehow goes back to its original value ???
    > > > Whats happening ? and how do I get the double to be the rounded
    > > > amount.

    > >
    > > What you have to remember is that the double type is inherently
    > > inaccurate... You say it goes back to its original value, but
    > > it doesn't -- it goes back to 0.12345678900000004. The original
    > > value was 0.1234567890. See, the double var already accrued a
    > > bit of error -- 0.00000000000000004 to be exact.
    > >
    > > Now, IIRC, the BigDecimal var still holds the original value,
    > > which is 0.12345678900000004, because you didn't do:
    > >
    > > big = big.setScale (6, BigDecimal.ROUND_HALF_UP));
    > >
    > > If you do that, I think you'll find that your final result is
    > > now about 0.123457, though possibly with some error. Hopefully
    > > someone will correct me if I'm wrong though.
    > >
    > > But generally speaking, get rid of the doubles if you need
    > > the accuracy. It's a lot clumsier to use, but it's ACCURATE.
    > > Doubles suck. :)

    --
    //*================================================================++
    || Russ Perry Jr 2175 S Tonne Dr #114 Arlington Hts IL 60005 ||
    || 847-952-9729 [NEW!] VIDEOGAME COLLECTOR! ||
    ++================================================================*//
    Russ Perry Jr, Jun 13, 2004
    #6
  7. (Dale King) wrote:
    > Russ Perry Jr wrote:
    > > (ChrisMM) wrote:
    > > > I have a double that I need to round to 6 dp, I thought I

    > could just
    > > > assign it to a BigDecimal, call its scale method and assign

    > the result
    > > > back to the double variable but something weird happens :-
    > > > This code ...
    > > >
    > > > double db = 0.1234567890;
    > > >
    > > > System.out.print(" Double = "+ db );
    > > > BigDecimal big = new BigDecimal( db );
    > > > System.out.print(" big = "+big);
    > > > System.out.print(" rounded big = "+big.setScale (6,
    > > > BigDecimal.ROUND_HALF_UP));
    > > > System.out.println(" back to double = " + new Double(
    > > > big.doubleValue() ));
    > > >
    > > > produces this output...
    > > >
    > > > Double = 0.12345678900000004
    > > > big =

    > 0.1234567890000000389694179148136754520237445831298828125
    > > > rounded big = 0.123457
    > > > back to double = 0.12345678900000004
    > > >
    > > > The double somehow goes back to its original value ???
    > > > Whats happening ? and how do I get the double to be the

    > rounded
    > > > amount.

    > >
    > > What you have to remember is that the double type is inherently
    > > inaccurate...


    > No it's not unless you mean it is innaccurate in the same way
    > that any finite representation is.


    That is, more or less, what I meant by "inherently inaccurate".

    [explanation deleted here]

    > > But generally speaking, get rid of the doubles if you need
    > > the accuracy. It's a lot clumsier to use, but it's ACCURATE.


    > What would you replac double with tha you consider accurate?
    > BigDecimal is not really more accurate. It can have many more
    > bits which means you can represent more numbers and it chooses to
    > represent integral multiples of powers of 10 so it can represent
    > fnite decimal numbers exactly. But is it really any more accurate
    > when there are still an infinite number of values you can't
    > represent?


    Perhaps then I should say that it's as accurate as I've ever needed
    it to be, and I suspect that given the approach I used in my posts
    (which is how we've used it at work), it will handle the example
    given by the original poster just fine.

    Since it uses more bits to represent the numbers, you also accrue
    less error in calculations involving them than you might with
    doubles, IIRC. I still say BigDecimals are better than doubles,
    at least in my experience of using them at work for insurance
    calculations.
    --
    //*================================================================++
    || Russ Perry Jr 2175 S Tonne Dr #114 Arlington Hts IL 60005 ||
    || 847-952-9729 [NEW!] VIDEOGAME COLLECTOR! ||
    ++================================================================*//
    Russ Perry Jr, Jun 15, 2004
    #7
  8. ChrisMM

    Dale King Guest

    Hello, Russ Perry Jr !
    You wrote:

    > (ChrisMM) wrote:
    > > I have a double that I need to round to 6 dp, I thought I

    could just
    > > assign it to a BigDecimal, call its scale method and assign

    the result
    > > back to the double variable but something weird happens :-
    > > This code ...
    > >
    > > double db = 0.1234567890;
    > >
    > > System.out.print(" Double = "+ db );
    > > BigDecimal big = new BigDecimal( db );
    > > System.out.print(" big = "+big);
    > > System.out.print(" rounded big = "+big.setScale (6,
    > > BigDecimal.ROUND_HALF_UP));
    > > System.out.println(" back to double = " + new Double(
    > > big.doubleValue() ));
    > >
    > > produces this output...
    > >
    > > Double = 0.12345678900000004
    > > big =

    0.1234567890000000389694179148136754520237445831298828125
    > > rounded big = 0.123457
    > > back to double = 0.12345678900000004
    > >
    > > The double somehow goes back to its original value ???
    > > Whats happening ? and how do I get the double to be the

    rounded
    > > amount.

    >
    > What you have to remember is that the double type is inherently
    > inaccurate...


    No it's not unless you mean it is innaccurate in the same way
    that any finite representation is. It shares the limitation that
    any finite representation does. There are an uncountably infinite
    number of real numbers. You cannot represent every number that
    exists between any two real numbers using a finite
    representation. Any finite representation can only represent a
    small, finite number of the vast, infinite number of numbers
    there are. In other words, for any representation you come up
    with there will be an infinite number of values that can't be
    represented exactly. The only question is which finite subset do
    you choose to represent exactly.

    The one that Java uses is the most common one which chooses a
    subset of those number that are an integer multiple of a power of
    two. We humans are used to thinkin in terms of numbers that are
    finite decimal representations. These would be integer multiples
    of powers of 10. Which is a super set of the integral multiples
    of powers of two. Therefore numbers like 0.1 hav no exact
    representation in Java's floating point system.

    Does this mean that it is inaccurate? That sort of depends on
    your definition of what you mean by accuracy. There is no such
    thing as computer math that is exact, which seems to be your
    standard for accuracy.

    > You say it goes back to its original value, but
    > it doesn't -- it goes back to 0.12345678900000004. The

    original
    > value was 0.1234567890. See, the double var already accrued a
    > bit of error -- 0.00000000000000004 to be exact.


    The value 0.1234567890 cannot be represented as an integral
    multiple of a power of 2 so the closest number that could be
    represented in that represenation. That number by the way is not
    0.12345678900000004, but a number close to that. When you print a
    double it does not give ou the exact value but the shortest
    decimal representation that is closer to the exact value than any
    othe double value.

    > But generally speaking, get rid of the doubles if you need
    > the accuracy. It's a lot clumsier to use, but it's ACCURATE.
    > Doubles suck. :)


    What would you replac double with tha you consider accurate?
    BigDecimal is not really more accurate. It can have many more
    bits which means you can represent more numbers and it chooses to
    represent integral multiples of powers of 10 so it can represent
    fnite decimal numbers exactly. But is it really any more accurate
    when there are still an infinite number of values you can't
    represent?

    --
    Dale King
    My Blog: http://daleking.homedns.org/Blog
    Dale King, Apr 15, 2006
    #8
  9. ChrisMM

    Dale King Guest

    Hello, Liz!
    You wrote:

    > Sounds like a lot of hastle just to do rounding. In the
    > old days of 'basic' we used to just multiply and divide
    > like this.
    >
    > b = int((a*100+5)/100); for two decimal places


    Which will give the same results as with Java. The issue is not
    the progamming language but the floating point representation,
    which is not designed to store all finite decimal numbers
    exactly.

    Usually what you want is a way to display it only to a certain
    number o decimal places, not to actually change the number.
    --
    Dale King
    My Blog: http://daleking.homedns.org/Blog
    Dale King, Apr 15, 2006
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?U3Vl?=
    Replies:
    2
    Views:
    1,165
    =?Utf-8?B?U3Vl?=
    Jun 26, 2006
  2. Shaguf
    Replies:
    0
    Views:
    325
    Shaguf
    Dec 24, 2008
  3. Shaguf
    Replies:
    0
    Views:
    430
    Shaguf
    Dec 26, 2008
  4. Shaguf
    Replies:
    0
    Views:
    217
    Shaguf
    Dec 26, 2008
  5. Shaguf
    Replies:
    0
    Views:
    199
    Shaguf
    Dec 24, 2008
Loading...

Share This Page