Java rounding with big Decimal.

C

ChrisMM

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
 
A

Andy Fish

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() ));
 
D

Dave Monroe

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.
 
R

Russ Perry Jr

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. :)
 
L

Liz

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 said:
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 (e-mail address removed) [NEW!] VIDEOGAME COLLECTOR! ||
++================================================================*//
 
R

Russ Perry Jr

Liz said:
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.
 
R

Russ Perry Jr

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]
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.
 
D

Dale King

Hello, Russ Perry Jr !
You said:
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?
 
D

Dale King

Hello, Liz!
You said:
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.
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top