4

This question is a follow up to the question (BigDecimal - to use new or valueOf) and its accepted answer.

To reiterate the question and answer for convenience:

BigDecimal has two methods:

double d = 0.1;
BigDecimal bd1 = new BigDecimal(d);
BigDecimal bd2 = BigDecimal.valueOf(d);

Which one is better? The answer shows that these methods do not produce the same result:

System.out.println(bd1);
System.out.println(bd2);

displays:

0.1000000000000000055511151231257827021181583404541015625
0.1

In the answer, the answerer states :

In general, if the result is the same (i.e. not in the case of BigDecimal, but in most other cases), then valueOf() should be preferred: it can do caching of common values (as seen on Integer.valueOf()) and it can even change the caching behaviour without the caller having to be changed. new will always instantiate a new value, even if not necessary (best example: new Boolean(true) vs. Boolean.valueOf(true)).

My question is: can we get some practical examples of when, specifically, we should use BigDecimal.valueOf() and when we should use new BigDecimal() ?? The answerer says "use valueOf() if the result is the same" but that doesn't help us to know when to use it (if ever?) for BigDecimal.

Specifically, which is preferable:

0.1000000000000000055511151231257827021181583404541015625

or

0.1

? And why?

Community
  • 1
  • 1
ryvantage
  • 13,064
  • 15
  • 63
  • 112
  • 3
    Well which result do you *want*? They do different things, in clearly documented ways. – Jon Skeet Jan 03 '14 at 18:09
  • 1
    How do you know which one you _want_? That's the core of the question. Would one ever be better than the other and why? – ryvantage Jan 03 '14 at 18:10
  • 1
    Better in which sense? Speed or correctness? `0.1` isn't precisely representable in two's complement floating point. – Elliott Frisch Jan 03 '14 at 18:16
  • 1
    @ryvantage Which one do you expect? Without any information, I would guess you want `0.1` but only you know what your requirements are. – Peter Lawrey Jan 03 '14 at 18:20
  • The one that's "better" is the one that leads to the entire program giving you the desired results. And we don't know what that program is supposed to do. – ajb Jan 03 '14 at 18:25
  • The purpose of the question was to extract possible scenarios as to why one would be preferable over the other. I have no exact specifications, this is really more of a theory question. – ryvantage Jan 03 '14 at 19:31

2 Answers2

12

Firstly, any time you convert from a double to BigDecimal you should take a step back and ask yourself whether you're really doing the right thing to start with. For example, if you've done this by parsing from a String to a double, then you should probably go straight from a String to a BigDecimal. I'm generally wary of this conversion, as it usually suggests someone is using an inappropriate type elsewhere.

Beyond that, they do different things: the constructor gives a BigDecimal which represents the exact same number as the double; valueOf gives a BigDecimal which represents the number given by the double value's canonical string representation. They're simply different things, and you should know which one you want when you try to use one.

Given that I'd try to avoid getting into this situation to start with, it's hard to give examples of when each is more appropriate, but if you've unavoidably converting text to a double, then lost the original text, but want to get back to that value, then using valueOf is likely to give you a better result. If you've performed a bunch of arithmetic operations on double values, then the constructor might be more appropriate. But it's really very context-sensitive, and as I say in most cases I'd probably choose a redesign rather than picking either option.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I can accept "this generally isn't a valid scenario" as an answer. `BigDecimal` is good for holding a `double` resulting from arithmetic, but how often do you have an **original** double that didn't result from arthimetic of integers? I guess I can't think of one situation... So yeah great point. – ryvantage Jan 03 '14 at 18:22
  • 1
    @ryvantage: No, it's not really "good for holding a `double` resulting from arithmetic" - `double` is! – Jon Skeet Jan 03 '14 at 18:30
  • The truth is that when I started programming I used `float` for everything; even for storing currency values (in dollars)... even for currency arithmetic! In the end, my calculations were always a few cents off. My clients didn't complain, but I wasn't happy. I've been learning a lot through the years and I've slowly been converting all of my code to use `BigDecimal` and to store currency as `int`s, but it's difficult to remember to convert to dollars for calculations and views so what I have now is a big jumbled mess of `double`s for some things, `int`s for others, and `BigDecimal`. – ryvantage Jan 04 '14 at 14:10
  • @ryvantage: Why not just store the currency as `BigDecimal`? All your currency arithmetic can be done using `BigDecimal`, so you don't need a jumble at all. – Jon Skeet Jan 04 '14 at 14:12
  • Anyways, my code used to use `BigDecimal.valueOf(double)` but I caught wind of that other question and refractored my code to use `new BigDecimal(double)` but then I realized I wasn't sure which is superior. Now I need to re-evaluate everything to see if I need to pass doubles to these `BigDecimal`s at all. But there's a ton of stuff being calculated on these dashboards I build (ratios, sales totals, etc) so it can be hard.. – ryvantage Jan 04 '14 at 14:12
  • partly because I don't want to run up the bill on my client fixing my newbie errors.. And, at that, I'll be fixing code I already supposedly "fixed." It gets difficult to explain to the end-user, especically when the numbers are really _only a few pennies off_ which they don't mind (but I do!!). – ryvantage Jan 04 '14 at 14:15
  • Ahh yes! I found a great example of needing to pass a `double` to `BigDecimal`. When you are pulling in from a `ResultSet` using `ResultSet#getDouble("column")`. If you pass that to a `BigDecimal`, you either need to use `valueOf()` or the constructor. – ryvantage Jan 04 '14 at 14:20
  • @ryvantage: Why would you not just use `ResultSet.getBigDecimal` to start with? – Jon Skeet Jan 04 '14 at 14:21
-1

Look at the sources of BigDecimal and it is kind of obvious that passing a double into valueOf is less efficient than calling the constructor

Daniel Nuriyev
  • 635
  • 6
  • 10