At work, we found a problem when trying to divide a large number by 1000. This number came from the database.
Say I have this method:
private static BigDecimal divideBy1000(BigDecimal dividendo) {
if (dividendo == null) return null;
return dividendo.divide(BigDecimal.valueOf(1000), RoundingMode.HALF_UP);
}
When I make the following call
divideBy1000(new BigDecimal("176100000"))
I receive the expected value of 176100. But if I try the line below
divideBy1000(new BigDecimal("1761e+5"))
I receive the value 200000. Why this occurs? Both numbers are the same with different representation and the latest is what I receive from database. I understand that, somehow, the JVM is dividing the number 1761 by 1000, rounding up and filling with 0's at the end.
What is the best way to avoid this kind of behavior? Keep in mind that the original number is not controlled by me.
As specified in javadoc, a BigDecimal
is defined by an integer value and a scale.
The value of the number represented by the BigDecimal is therefore (unscaledValue × 10^(-scale)).
So BigDecimal("1761e+5")
has scale -5 and BigDecimal(176100000)
has scale 0.
The division of the two BigDecimal
is done using the -5 and 0 scales respectively because the scales are not specified when dividing. The divide
documentation explains why the results are different.
divide
public BigDecimal divide(BigDecimal divisor)
Returns a
BigDecimal
whose value is(this / divisor)
, and whose preferred scale is(this.scale() - divisor.scale())
; if the exact quotient cannot be represented (because it has a non-terminating decimal expansion) anArithmeticException
is thrown.Parameters:
divisor
- value by which this BigDecimal is to be divided.Returns:
this / divisor
Throws:
ArithmeticException
— if the exact quotient does not have a terminating decimal expansionSince:
1.5
If you specify a scale when dividing, e.g. dividendo.divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP)
you will get the same result.