Rounding mismatch between ASP .net C# Decimal to Java Double
The problem comes from how doubles vs decimals are stored and represented in memory. See these links for more specifics: Doubles Decimals
Let's take a look at how they each work in your code. Using doubles, with arguments of 8.725 and 0.05. number / roundPrecision
gives 174.499...
, since doubles aren't able to exactly represent 174.5. With decimals number / roundPrecision
gives 174.5
, decimals are able to represent this exactly. So then when 174.499...
gets rounded, it gets rounded down to 174
instead of 175
.
Using BigDecimal
is a step in the right direction. There is an issue with how it's being used in your code however. The problem comes when you're creating the BigDecimal value.
BigDecimal b = new BigDecimal(number / roundPrecision);
The BigDecimal
is being created from a double, so the imprecision is already there. If you're able to create the BigDecimal
arguments from a string that would be much better.
public static BigDecimal roundToPrecision(BigDecimal number, BigDecimal roundPrecision) {
if (roundPrecision.signum() == 0)
return number;
BigDecimal numberDecimalMultiplier = number.divide(roundPrecision, RoundingMode.HALF_DOWN).setScale(0, RoundingMode.HALF_UP);
return numberDecimalMultiplier.multiply(roundPrecision);
}
BigDecimal n = new BigDecimal("-8.7250");
BigDecimal p = new BigDecimal("0.05");
BigDecimal r = roundToPrecision(n, p);
If the function must take in and return doubles:
public static double roundToPrecision(double number, double roundPrecision)
{
BigDecimal numberBig = new BigDecimal(number).
setScale(10, BigDecimal.ROUND_HALF_UP);
BigDecimal roundPrecisionBig = BigDecimal.valueOf(roundPrecision);
if (roundPrecisionBig.signum() == 0)
return number;
BigDecimal numberDecimalMultiplier = numberBig.divide(roundPrecisionBig, RoundingMode.HALF_DOWN).setScale(0, RoundingMode.HALF_UP);
return numberDecimalMultiplier.multiply(roundPrecisionBig).doubleValue();
}
Keep in mind that doubles cannot exactly represent the same values which decimals can. So the function returning a double cannot have the exact output as the original C# function which returns decimals.