Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set specific precision of a BigDecimal

I have an XSD that requires me to use a BigDecimal for a lat/lon. I currently have the lat/lon as doubles, and convert them to BigDecimal, but I am only required to use about 12 places of precision. I have not been able to figure out how to set that. Can anyone help me with this?

like image 989
Jason Avatar asked Feb 28 '12 13:02

Jason


People also ask

What is default precision of BigDecimal in Java?

BigDecimal represents decimal floating-point numbers of arbitrary precision. By default, the precision approximately matches that of IEEE 128-bit floating point numbers (34 decimal digits, HALF_EVEN rounding mode).

What does precision mean in BigDecimal?

The precision is the number of digits in the unscaled value.

What is scale and precision in BigDecimal?

A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale.

How do I stop rounding in BigDecimal?

56 if you use BigDecimal newValue = myBigDecimal. setScale(2, RoundingMode. DOWN); " This statement is true for HALF_DOWN not for DOWN mode.


2 Answers

You can use setScale() e.g.

double d = ... BigDecimal db = new BigDecimal(d).setScale(12, BigDecimal.ROUND_HALF_UP); 
like image 186
Peter Lawrey Avatar answered Sep 22 '22 06:09

Peter Lawrey


The title of the question asks about precision. BigDecimal distinguishes between scale and precision. Scale is the number of decimal places. You can think of precision as the number of significant figures, also known as significant digits.

Some examples in Clojure.

(.scale     0.00123M) ; 5 (.precision 0.00123M) ; 3 

(In Clojure, The M designates a BigDecimal literal. You can translate the Clojure to Java if you like, but I find it to be more compact than Java!)

You can easily increase the scale:

(.setScale 0.00123M 7) ; 0.0012300M 

But you can't decrease the scale in the exact same way:

(.setScale 0.00123M 3) ; ArithmeticException Rounding necessary 

You'll need to pass a rounding mode too:

(.setScale 0.00123M 3 BigDecimal/ROUND_HALF_EVEN) ; ; Note: BigDecimal would prefer that you use the MathContext rounding ; constants, but I don't have them at my fingertips right now. 

So, it is easy to change the scale. But what about precision? This is not as easy as you might hope!

It is easy to decrease the precision:

(.round 3.14159M (java.math.MathContext. 3)) ; 3.14M 

But it is not obvious how to increase the precision:

(.round 3.14159M (java.math.MathContext. 7)) ; 3.14159M (unexpected) 

For the skeptical, this is not just a matter of trailing zeros not being displayed:

(.precision (.round 3.14159M (java.math.MathContext. 7))) ; 6  ; (same as above, still unexpected) 

FWIW, Clojure is careful with trailing zeros and will show them:

4.0000M ; 4.0000M (.precision 4.0000M) ; 5 

Back on track... You can try using a BigDecimal constructor, but it does not set the precision any higher than the number of digits you specify:

(BigDecimal. "3" (java.math.MathContext. 5)) ; 3M (BigDecimal. "3.1" (java.math.MathContext. 5)) ; 3.1M 

So, there is no quick way to change the precision. I've spent time fighting this while writing up this question and with a project I'm working on. I consider this, at best, A CRAZYTOWN API, and at worst a bug. People. Seriously?

So, best I can tell, if you want to change precision, you'll need to do these steps:

  1. Lookup the current precision.
  2. Lookup the current scale.
  3. Calculate the scale change.
  4. Set the new scale

These steps, as Clojure code:

(def x 0.000691M) ; the input number (def p' 1) ; desired precision (def s' (+ (.scale x) p' (- (.precision x)))) ; desired new scale (.setScale x s' BigDecimal/ROUND_HALF_EVEN) ; 0.0007M 

I know, this is a lot of steps just to change the precision!

Why doesn't BigDecimal already provide this? Did I overlook something?

like image 31
David J. Avatar answered Sep 23 '22 06:09

David J.