Currently i have this method:
static boolean checkDecimalPlaces(double d, int decimalPlaces){
if (d==0) return true;
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
check = Math.round(check);
check = check/multiplier;
return (d==check);
}
But this method fails for checkDecmialPlaces(649632196443.4279, 4)
probably because I do base 10 math on a base 2 number.
So how can this check be done correctly?
I thought of getting a string representation of the double value and then check that with a regexp - but that felt weird.
EDIT: Thanks for all the answers. There are cases where I really get a double and for those cases I implemented the following:
private static boolean checkDecimalPlaces(double d, int decimalPlaces) {
if (d == 0) return true;
final double epsilon = Math.pow(10.0, ((decimalPlaces + 1) * -1));
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
long checkLong = (long) Math.abs(check);
check = checkLong / multiplier;
double e = Math.abs(d - check);
return e < epsilon;
}
I changed the round
to a truncation. Seems that the computation done in round
increases the inaccuracy too much. At least in the failing testcase.
As some of you pointed out if I could get to the 'real' string input I should use BigDecimal
to check and so I have done:
BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;
The double
value I get comes from the Apache POI API that reads excel files. I did a few tests and found out that although the API returns double
values for numeric cells I can get a accurate representation when I immediately format that double
with the DecimalFormat
:
DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
// don't use grouping for numeric-type cells
decimalFormat.setGroupingUsed(false);
decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
value = decimalFormat.format(numericValue);
This also works for values that can't be represented exactly in binary format.