Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any neat way to limit significant figures with BigDecimal

I want to round a Java BigDecimal to a certain number of significant digits (NOT decimal places), e.g. to 4 digits:

12.3456 => 12.35
123.456 => 123.5
123456 => 123500

etc. The basic problem is how to find the order of magnitude of the BigDecimal, so I can then decide how many place to use after the decimal point.

All I can think of is some horrible loop, dividing by 10 until the result is <1, I am hoping there is a better way.

BTW, the number might be very big (or very small) so I can't convert it to double to use Log on it.

like image 720
Martin McBride Avatar asked Sep 27 '11 16:09

Martin McBride


3 Answers

Why not just use round(MathContext)?

BigDecimal value = BigDecimal.valueOf(123456);
BigDecimal wantedValue = value.round(new MathContext(4, RoundingMode.HALF_UP));
like image 195
Kru Avatar answered Nov 12 '22 19:11

Kru


The easierst solution is:

  int newScale = 4-bd.precision()+bd.scale();
  BigDecimal bd2 = bd1.setScale(newScale, RoundingMode.HALF_UP);

No String conversion is necessary, it is based purely on BigDecimal arithmetic and therefore as efficient as possible, you can choose the RoundingMode and it is small. If the output should be a String, simply append .toPlainString().

like image 12
A.H. Avatar answered Nov 12 '22 20:11

A.H.


You can use the following lines:

int digitsRemain = 4;

BigDecimal bd = new BigDecimal("12.3456");
int power = bd.precision() - digitsRemain;
BigDecimal unit = bd.ulp().scaleByPowerOfTen(power);
BigDecimal result = bd.divideToIntegralValue(unit).multiply(unit);

Note: this solution always rounds down to the last digit.

like image 5
Howard Avatar answered Nov 12 '22 20:11

Howard