The Evil BigDecimal Constructor

One of the first things that most people learn as software developers, quite probably by accident, is that thanks to the binary representation that computers use for numbers, floating point operations are really kind of screwed up. So Java programmers learn early that if the calculation involves floating point numbers, it’s better to use java.math.BigDecimal to preserve all those fractions exact value to get the correct calculation result.

Which is correct. Except that some developers mistakenly use the BigDecimal(double) constructor, like the snippets below:


js> importPackage(java.math);
js> var oneTenth = new BigDecimal(0.1);
js> var oneMillion = new BigDecimal(1000000);
js> oneTenth.multiply(oneMillion)
100000.0000000000055511151231257827021181583404541015625000000

Which brings them back to square one, really. The reason is that when you call BigDecimal(double), the BigDecimal instance that you get back is the exact representation of that double value you’re passing in. In other words, you’re just reproducing the inaccuracy that you get when you try to represent 0.1 in binary. Pity.

To get what you really want, remember to use the other constructor, which accept a String. This is more like it:


js> var oneTenth = new BigDecimal("0.1");
js> var oneMillion = new BigDecimal(1000000);
js> oneTenth.multiply(oneMillion)
100000.0

Note that we can still pass 1000000 to BigDecimal, because we can represent integers in binary exactly. Likewise, those fractions that can be represented exactly in binary (such as 0.5, 0.25, 0.125, 0.0625, and so on) are fine:


js> var oneSixtyFourth = new BigDecimal(0.015625);
js> oneSixtyFourth.multiply(oneMillion)
15625.000000

But why bother wasting your brain cycles to keep track of this? It’s much easier to just remember this simple rule: when you want exact calculation results the way you want it, use BigDecimal(String). When in doubt, use BigDecimal(String). In fact, I can’t think of a case where one has to use BigDecimal(double). If you know of a legitimate case for using it, I’ll be grateful if you leave a comment about it.

8 thoughts on “The Evil BigDecimal Constructor

  1. I’m not sure… although at least I understand why some developers still use BigDecimal(double). This class was introduced in Java 1.1, and the documentation for BigDecimal(double) in that version didn’t say anything to indicate its behaviour. Only starting from 1.2 did the documentation start document this.

  2. “in that version didn’t say anything to indicate its behaviour.”

    Maybe because if you know enough to be using BigDecimal in the first place, you should already know what’s going on? Kinda funny because this is one problem COBOL solved 40 years ago. Thanks Grace!

  3. Most programmers don’t read the documentation or take the time to really understand a language. It’s a sad truth.
    I corrected the same floating point use bug (using a double for validating an input money) in C and later in a full rewrite of the app in Java, by different programmers. And a similar case in a different app using double for formating a Money field.
    Awful.

  4. Yeah, and sadly… those who won’t read the documentation or take the time to understand the language most probably won’t bother to read blogs like this either 😦

  5. Just wanted to say thanks for your article on the “The Evil BigDecimal Constructor” – it was well written and easy to understand and helped me with my problem. Thanks a BigDecimal(“1000000”)!

    Al

Leave a reply to sid Cancel reply