В настоящее время у меня есть этот метод:
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);
}
Но этот метод не работает для checkDecmialPlaces(649632196443.4279, 4)
, вероятно, потому, что я делаю математику 10 с номером 2.
Так как же правильно выполнить эту проверку?
Я думал о том, чтобы получить строковое представление двойного значения, а затем проверить это с помощью регулярного выражения - но это было странно.
EDIT:
Спасибо за ответы на все вопросы. Есть случаи, когда я действительно получаю удвоение, и для этих случаев я реализовал следующее:
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;
}
Я изменил round
на усечение. Кажется, что вычисления, сделанные в round
, слишком сильно увеличивают неточность. По крайней мере, в неудачном тестовом примере.
Как некоторые из вас указали, если бы я мог получить «реальный» ввод строки, я должен использовать BigDecimal
для проверки, и я сделал:
BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;
Полученное мной значение double
исходит из API-интерфейса Apache POI, который читает файлы Excel. Я провел несколько тестов и обнаружил, что, хотя API возвращает double
значения для числовых ячеек, я могу получить точное представление, когда немедленно отформатирую это double
с помощью 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);
Это также работает для значений, которые не могут быть точно представлены в двоичном формате.