How to get the exact value in BigDecimal?

1k Views Asked by At

I want to get a BigDecimal value with the following attributes:

  • Rounding mode: Halfe-even
  • number of digits after the point: 2

I have the following code:

public BigDecimal standardDeviation() {
            MathContext mc = new MathContext (4,RoundingMode.HALF_EVEN);
            return new BigDecimal(Math.sqrt(variance().doubleValue()), mc);
        }

On test when i send some values, I got the following failure:

invalid standard deviation ==> expected: <16.73> but was: <16.72>

How can I solvw this?

1

There are 1 best solutions below

0
On

Summarizing the comments:

invalid standard deviation ==> expected: <16.73> but was: <16.72>

Note that you very likely have a misconception on the rounding mode here.

Note that JavaDoc on HALF_EVEN:

"Behaves as for RoundingMode.HALF_UP if the digit to the left of thediscarded fraction is odd; behaves as for RoundingMode.HALF_DOWN if it's even"

That means a number like 16.725 would be rounded down rather than up so with HALF_EVEN the result will be 16.72.

How can I convert 95 (BigDecimal) to 95.00 ?

From a numeric perspective there is no difference between 95 and 95.00 since the trailing zeros are as insignificant as leading zeros are. In that sense even 0095.0000 would be the same numeric value.

When you're dealing with BigDecimal your first goal would normally be to get calculations and thus numerical values that don't suffer from "arbitrary" precision issues (indefinite precision is not supported but it can be set to a fixed value) and are as accurate as possible.

Hence if you create a BigDecimal from the numbers 95, 95.0 or even the string "95.00" they wil have the same value though.

However, they are not equal since internally the numbers also have a scale, i.e. 95 and 95.0 would normally be represented internally as the integer 95 and a scale of 0, which means the decimal point would not have to be moved. On the other hand "95.00" would be represented as the number 9500 and a scale of 2 which means to get the actual number you'd need to move the decimal point by 2 digits to the left.

That being said, if you want to check BigDecimals for equality don't use equals() as this also considers the scale but use compareTo() == 0 since that will compare the numerical value only.

I am working on a payment system, I need to return the numbers with the 2 digits after the point even if the number is like 95.

In general this is more of a formatting problem. Users of your system don't care how many fractional digits there are internally as long as calculations are done correctly. When you need to show a number to the user you need to convert it to a string and that's where formatting kicks in.

To generate a nicely formatted String you could use any of the methods based on java.utilFormatter e.g. String.format(printf("%.2f", bigDecimal);

Finally, there is a way to actually change the output of BigDecimal.toString() to 95.00 but I'd not recommend using it for that purpose: try new BigDecimal(95).setScale(2).toString().

Instead, format the output to the number of fraction digits you need and use methods like setScale() only to round correctly, e.g. if you want to round to 2 fraction digits try new BigDecimal(16.725).setScale(2, RoundingMode.HALF_UP)