Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BigDecimal - to use new or valueOf

I came across two ways of getting BigDecimal object out of a double d.

  1. new BigDecimal(d)
  2. BigDecimal.valueOf(d)

Which would be a better approach? Would valueOf create a new object?

In general (not just BigDecimal), what is recommended - new or valueOf?

like image 984
Manish Mulani Avatar asked Aug 25 '11 06:08

Manish Mulani


People also ask

How do I use BigDecimal valueOf?

valueOf(long unscaledVal, int scale) is an inbuilt method in Java that is used to translate a long unscaled value and an int scale into a BigDecimal. This “static factory method” is provided in preference to a (long, int) constructor because it allows for reuse of frequently used BigDecimal values.

How do I assign a value to BigDecimal?

In order to add a BigDecimal to another BigDecimal, use add(BigDecimal augend) API method, that returns a BigDecimal whose value is (this + augend), and whose scale is max(this. scale(), augend.

Why should we use BigDecimal?

The BigDecimal class provides operations on double numbers for arithmetic, scale handling, rounding, comparison, format conversion and hashing. It can handle very large and very small floating point numbers with great precision but compensating with the time complexity a bit.

Which is more accurate BigDecimal or double?

A BigDecimal is an accurate way of expressing numbers. A Double has a reliable accuracy. Going with doubles of various magnitudes (say d1=1000.0 and d2=0.001) could occur in the 0.001 being dropped collectively when summing as the variation in magnitude is so large. With BigDecimal this would not occur.


2 Answers

Those are two separate questions: "What should I use for BigDecimal?" and "What do I do in general?"

For BigDecimal: this is a bit tricky, because they don't do the same thing. BigDecimal.valueOf(double) will use the canonical String representation of the double value passed in to instantiate the BigDecimal object. In other words: The value of the BigDecimal object will be what you see when you do System.out.println(d).

If you use new BigDecimal(d) however, then the BigDecimal will try to represent the double value as accurately as possible. This will usually result in a lot more digits being stored than you want. Strictly speaking, it's more correct than valueOf(), but it's a lot less intuitive.

There's a nice explanation of this in the JavaDoc:

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

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

like image 76
Joachim Sauer Avatar answered Sep 21 '22 04:09

Joachim Sauer


If you are using your BigDecimal objects to store currency values, then I strongly recommend that you do NOT involve any double values anywhere in their calculations.

As stated in another answer, there are known accuracy issues with double values and these will come back to haunt you big time.

Once you get past that, the answer to your question is simple. Always use the constructor method with the String value as the argument to the constructor, as there is no valueOf method for String.

If you want proof, try the following:

BigDecimal bd1 = new BigDecimal(0.01); BigDecimal bd2 = new BigDecimal("0.01"); System.out.println("bd1 = " + bd1); System.out.println("bd2 = " + bd2); 

You'll get the following output:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375 bd2 = 0.01 

See also this related question

like image 30
DuncanKinnear Avatar answered Sep 24 '22 04:09

DuncanKinnear