• Post Reply Bookmark Topic Watch Topic
  • New Topic

Rounding in BigDecimal  RSS feed

 
Kevin Tysen
Ranch Hand
Posts: 255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I used the class BigDecimal and used the field ROUNDHALFUP in order to round up a number, but it didn't round up.
More specifically, the number was the double obtained by dividing 1942 by 40. If you divide 1942 by 40 on paper, you get 48.55 exactly, so I figured that using ROUNDHALFUP would give me 48.6 but instead I got 48.5.
I thought about it a bit, and I assume that dividing 1942.0 by 40.0 would give a double very close to 48.55, but not exactly because the numbers are all binary instead of base 10. Also, although 48.5 would be exact, 48.6 would not be exact.
What I used to do to round to the nearest tenth was like this:

double a;
double b;
double d = 10.0 * a/b + 0.5;
int result = (int) d;
// then change result into a string, stick a period in just before the last digit on the right, and add a zero on the left if necessary

You know what I mean, I think. But that takes up a lot of space in a program. Using BigDecimal saved space, but I got a result I did not want. There must be some simple way to round accurately to the nearest tenth. Anyone know what it is?
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Are you using floating-point arithmetic? If you pass a double to the constructor of a BigDecimal you can permanently immortalise any arithmetical errors.
campbell@linux-pgix:~/java> java RoundDemo 1942 40
48.5499999999999971578290569595992565155029296875
campbell@linux-pgix:~/java> java RoundDemo 1942.0 40.0
48.5499999999999971578290569595992565155029296875
campbell@linux-pgix:~/java>
So you would actually round to 48.5, not 48.6.
 
Kevin Tysen
Ranch Hand
Posts: 255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is the actual line in my program:

writer.write((new BigDecimal(tts / nw)).setScale(2, BigDecimal.ROUND_HALF_UP).toString());

And tts and nw are both doubles.

What do you mean by floating point arithmetic? Is that a float instead of a double?
What do you mean by "immortalize"?

 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Both float and double use floating-point arithmetic, which is inherently imprecise (look at these FAQs (no 20) and links). So when you divide 1942.0 by 40.0 you don't get 48.55, but something slightly less, in fact 48.5499999999999971578290569595992565155029296875.
If you pass that double to the BigDecimal constructor, you make the imprecision immortal, make it permanent, preserve it for ever, maintain it until the application terminates, can't get rid of it. So the BigDecimal will have the value of 48.5499999999999971578290569595992565155029296875 not 48.55.

TryThat should come out as 48.55, and should round to 48.6.
And instead of new BigDecimal(123.456) which can be imprecise, write new BigDecimal("123.456"). The String representation of the number will be interpreted precisely as 123.456.
It says in the The API documentation that a BigDecimal stores its values as whole numbers, so its arithmetic can be precise, just as integer arithmetic is precise. Note what it says in the divide method about Exceptions and precision.
 
Nandu Jawale
Greenhorn
Posts: 23
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


 
Kevin Tysen
Ranch Hand
Posts: 255
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I used the .divide(BigDecimal divisor, int scale, int roundingMode) method in class BigDecimal and it worked.
Thank you!
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're welcome
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!