Двойное значение для округления в Java
У меня двойное значение = 1.068879335
я хочу, чтобы округлить его только с двумя десятичными значениями, как 1,07.
Я пытался так
DecimalFormat df=new DecimalFormat("0.00");
String formate = df.format(value);
double finalValue = Double.parseDouble(formate) ;
это дает мне следующее исключение
java.lang.NumberFormatException: For input string: "1,07"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
at java.lang.Double.parseDouble(Double.java:510)
может кто-нибудь сказать мне, что не так с моим кодом.
наконец, мне нужно finalValue = 1.07;
9 ответов
Запишите запятую в вашей строке: "1,07". DecimalFormat
использует специфическую для локали строку-разделитель, в то время как Double.parseDouble()
не. Так как вы живете в стране, где десятичный разделитель равен ",", вы не можете разобрать свой номер обратно.
Тем не менее, вы можете использовать тот же DecimalFormat
разобрать его обратно:
DecimalFormat df=new DecimalFormat("0.00");
String formate = df.format(value);
double finalValue = (Double)df.parse(formate) ;
Но вы действительно должны сделать это вместо этого:
double finalValue = Math.round( value * 100.0 ) / 100.0;
Примечание. Как уже указывалось, использовать плавающую точку следует только в том случае, если вам не требуется точный контроль точности. (Финансовые расчеты являются основным примером того, когда их не следует использовать.)
Live @ решение Сергея, но с целочисленным делением.
double value = 23.8764367843;
double rounded = (double) Math.round(value * 100) / 100;
System.out.println(value +" rounded is "+ rounded);
печать
23.8764367843 rounded is 23.88
РЕДАКТИРОВАТЬ: Как указывает Сергей, не должно быть никакой разницы между умножением double * int и double * double и делением double / int и double / double. Я не могу найти пример, где результат отличается. Однако в x86/x64 и других системах есть специальная инструкция машинного кода для смешанных значений типа double,int, которые, как мне кажется, использует JVM.
for (int j = 0; j < 11; j++) {
long start = System.nanoTime();
for (double i = 1; i < 1e6; i *= 1.0000001) {
double rounded = (double) Math.round(i * 100) / 100;
}
long time = System.nanoTime() - start;
System.out.printf("double,int operations %,d%n", time);
}
for (int j = 0; j < 11; j++) {
long start = System.nanoTime();
for (double i = 1; i < 1e6; i *= 1.0000001) {
double rounded = (double) Math.round(i * 100.0) / 100.0;
}
long time = System.nanoTime() - start;
System.out.printf("double,double operations %,d%n", time);
}
Печать
double,int operations 613,552,212
double,int operations 661,823,569
double,int operations 659,398,960
double,int operations 659,343,506
double,int operations 653,851,816
double,int operations 645,317,212
double,int operations 647,765,219
double,int operations 655,101,137
double,int operations 657,407,715
double,int operations 654,858,858
double,int operations 648,702,279
double,double operations 1,178,561,102
double,double operations 1,187,694,386
double,double operations 1,184,338,024
double,double operations 1,178,556,353
double,double operations 1,176,622,937
double,double operations 1,169,324,313
double,double operations 1,173,162,162
double,double operations 1,169,027,348
double,double operations 1,175,080,353
double,double operations 1,182,830,988
double,double operations 1,185,028,544
Проблема заключается в том, что вы используете локализующий форматер, который генерирует десятичную точку для конкретной локали, которая в вашем случае равна ",". Но Double.parseDouble() ожидает нелокализованный двойной литерал. Вы можете решить свою проблему, используя метод синтаксического анализа для конкретной локали или изменив локаль вашего форматера на что-то, использующее "." в качестве десятичной точки. Или, что еще лучше, избегайте ненужного форматирования, используя что-то вроде этого:
double rounded = (double) Math.round(value * 100.0) / 100.0;
В том, что вы пытаетесь сделать, что-то в корне не так. Двоичные значения с плавающей запятой не имеют десятичных разрядов. Вы не можете осмысленно округлить от одного до заданного количества десятичных знаков, потому что большинство "округлых" десятичных значений просто не могут быть представлены в виде двоичной дроби. Вот почему никогда не следует использовать float
или же double
представлять деньги.
Так что если вы хотите, чтобы в вашем результате были десятичные знаки, этот результат должен быть либо String
(который вы уже получили с DecimalFormat
) или BigDecimal
(который имеет setScale()
метод, который делает именно то, что вы хотите). В противном случае результат не может быть таким, каким вы хотите его видеть.
Прочитайте Руководство с плавающей точкой для получения дополнительной информации.
Попробуйте это: org.apache.commons.math3.util.Precision.round(double x, int scale)
См. http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html
Домашняя страница библиотеки математики Apache Commons: http://commons.apache.org/proper/commons-math/index.html
Внутренняя реализация этого метода:
public static double round(double x, int scale) {
return round(x, scale, BigDecimal.ROUND_HALF_UP);
}
public static double round(double x, int scale, int roundingMethod) {
try {
return (new BigDecimal
(Double.toString(x))
.setScale(scale, roundingMethod))
.doubleValue();
} catch (NumberFormatException ex) {
if (Double.isInfinite(x)) {
return x;
} else {
return Double.NaN;
}
}
}
Это невозможно в запрошенном виде, поскольку существуют числа с двумя десятичными разрядами, которые не могут быть точно выражены с использованием чисел с плавающей запятой IEEE (например, 1/10 = 0,1 не может быть выражено как Double
или же Float
). Форматирование всегда должно выполняться как последний шаг перед тем, как представить результат пользователю.
Я думаю, вы спрашиваете, потому что вы хотите иметь дело с денежными показателями. Нет надежного способа сделать это с числами с плавающей запятой, вы должны подумать о переходе на арифметику с фиксированной запятой. Вероятно, это означает, что все расчеты производятся в "центах", а не в "долларах".
double TotalPrice=90.98989898898;
DecimalFormat format_2Places = new DecimalFormat("0.00");
TotalPrice = Double.valueOf(format_2Places.format(TotalPrice));
Вы можете попытаться определить новый DecimalFormat и использовать его как результат Double для новой двойной переменной.
Пример приведен, чтобы вы поняли, что я только что сказал.
double decimalnumber = 100.2397;
DecimalFormat dnf = new DecimalFormat( "#,###,###,##0.00" );
double roundednumber = new Double(dnf.format(decimalnumber)).doubleValue();
Если вы не хотите использовать DecimalFormat (например, из-за его эффективности) и хотите общее решение, вы также можете попробовать этот метод, который использует масштабированное округление:
public static double roundToDigits(double value, int digitCount) {
if (digitCount < 0)
throw new IllegalArgumentException("Digit count must be positive for rounding!");
double factor = Math.pow(10, digitCount);
return (double)(Math.round(value * factor)) / factor;
}
Вы можете использовать формат, как здесь,
public static double getDoubleValue(String value,int digit){
if(value==null){
value="0";
}
double i=0;
try {
DecimalFormat digitformat = new DecimalFormat("#.##");
digitformat.setMaximumFractionDigits(digit);
return Double.valueOf(digitformat.format(Double.parseDouble(value)));
} catch (NumberFormatException numberFormatExp) {
return i;
}
}