Java Traps: Big Decimal

Author: Kasper B. Graversen, 22/06/08
Keywords: Java, Java traps trail, Numbers, BigDecimal
Abstract: This article documents the traps and pitfalls around using the BigDecimal class
subscribe to my RSS feed


Bookmark and Share


Java Traps: Big Decimal

Fortunately, it's now almost common sense for programmers not to use the simple types float's and double's for representing monetary values (or any other value preferably :-) due to the impression surrounded with these types. float's and double's are further restricted by a fixed set of bits to represent them, hence only a limited set of numbers can be held in these types. Armed with this knowledge, fun code examples can be produced such as the one from bytes.com
// Bill Gates has 100,000,000,000 in his savings account. His bank's
// statement is printed using:
#include <stdio.h>
int main(void) {
	float y = 1e11F;
	printf("Your balance is %.2f\n", y);
	return 0;
}

// The bank's computer prints the result as:
Your balance is 99999997952.00

Yes it's C code not Java, but fun never the less. The salvation seems to be the java.math.BigDecimal class as it has not only precision but is not represented by a fixed set of bits. Let's have some fun comparing its performance to double and discover some of the traps that lay in store for you the first time you use BigDecimal.

Printing

This one struck me and some co-workers when we had to convert some numbers to and from XML in a low-level fashion. First let's revisit the double and see how it performs when printing
double d1 = 2.2;
double d2 = 2.3;
System.out.println(d1 + d2);

>> 4.5

Now lets try the same with a BigDecimal
double d1 = 2.2;
double d2 = 2.3;
System.out.println(new BigDecimal(d1));
System.out.println(new BigDecimal(d2));

>> 2.20000000000000017763568394002504646778106689453125
>> 2.29999999999999982236431605997495353221893310546875

While XML in itself is not very pleasant, these numbers surely shouldn't make it to any front-end (yes you guessed it, the XML was for web services!). The numbers do not very accurate either. Any accountant would be shaking in his pants, should he see this code example! Notice the random nature of the numbers. Seemingly d1 > 2.2 while d2 < 2.3. This is due to the (imprecise) internal representation of doubles in the JVM as documented in Java Double trap. Let's have some fun adding the two numbers together...
System.out.println(new BigDecimal(d1).add(new BigDecimal(d2)));

>> 4.50000000000000000000000000000000000000000000000000

The addition actually came out nicely.. well, except for the number of digits displayed is. Especially considering the result 4.5 we got from out calculation using double...

Solution

There are ways to avoid the problem.
  • Always use strings when instantiating BigDecimal
  • Or, don't rely on toString() call doubleValue() instead.
Let's have a go
System.out.println(new BigDecimal("" + d1));
System.out.println(new BigDecimal("" + d2));
System.out.println(new BigDecimal("" + d1).add(new BigDecimal("" + d2)));
System.out.println(new BigDecimal(d1).add(new BigDecimal(d2)).doubleValue());

>> 2.2
>> 2.3
>> 4.5
>> 4.5

Voula! Curious readers should seek more more info on javadoc BigDecimal

Math

Another trap you quickly realize is that you can't use +, - etc since you are operating on objects. Hence, to add numbers you must turn to the add() method. For good reasons (memory usage) add() in BigDecimal was the first add() method I've encountered in the Java API which behaves differently to all other add()'s so be careful ;-)
BigDecimal bd = new BigDecimal("2.3");
bd.add( new BigDecimal("2.3") );
System.out.println(bd);

>> 2.3

Adding a number does not change the state of the object referenced by the bd reference.

Solution

Instead a new object is returned. Hence we have to say
BigDecimal bd = new BigDecimal("2.3");
bd = bd.add( new BigDecimal("2.3") );
System.out.println(bd);

>> 4.6

JDK1.4.2 and 1.5 differences

As documented by Joseph D. Darcy in his quality blog, significant changes has been made to BigDecimal across version 1.4.2 and 1.5. The details are beyon the scope of this article, so I'll recommend interested audience to give it a click. That's all for this time. If you've been trapped in other ways using the BigDecimal api, please let me know and I'll extend this section...

Have fun...



Comments

If you have any comments to this article, please drop me a mail at firstclassthoughts at gmail dot com please indicate if I can't publish whole or parts of your comment on the site.


If you like this site consider subscribing to my RSS feed or how about subscribing by Email.


Help spread the word

Share this post on your favorite social bookmarking sites:
If you enjoyed this article, found it thought provoking, educative or otherwise good, please link to this page from your page or social bookmarking page. If you have any texts you think are worth publishing on First Class Thoughts, don't hesitate to send me a mail! Quality always welcome.


Bookmark and Share


The most recent contributions
20/05/09 Board Game Jungle speed / Arriba Review of the cool game "Jungle Speed" aka. "Arriba".
16/05/09 Danish Twin words "Twin words" are words that not only have multiple meanings, they must be composed next to each other in meaningful sentences. This article explores the concept of twin words.
14/05/09 English Twin words "Twin words" are words that not only have multiple meanings, they must be composed next to each other in meaningful sentences. This article explores the concept of twin words.
04/05/09 'Office space' extras Crazy stuff about the funny movie "Office space".
Nothing of interest? Try browsing the entire article archive...