Двойное значение для округления в Java - PullRequest
35 голосов
/ 25 января 2011

У меня есть двойное значение = 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;

Ответы [ 10 ]

78 голосов
/ 25 января 2011

Обратите внимание на запятую в вашей строке: "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;

Примечание: Как уже указывалось, вы должны использовать плавающую точку, только если вам не нужнаТочный контроль над точностью.(Финансовые расчеты являются основным примером того, когда не , чтобы их использовать.)

20 голосов
/ 25 января 2011

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
7 голосов
/ 25 января 2011

Проблема в том, что вы используете локализатор форматирования, который генерирует десятичную точку, специфичную для локали, которая в вашем случае равна ",". Но Double.parseDouble () ожидает нелокализованный двойной литерал. Вы можете решить вашу проблему, используя метод синтаксического анализа для конкретной локали или изменив локаль вашего форматера на что-то, что использует «.» в качестве десятичной точки. Или, что еще лучше, избегайте ненужного форматирования, используя что-то вроде этого:

double rounded = (double) Math.round(value * 100.0) / 100.0;
4 голосов
/ 25 января 2011

В том, что вы пытаетесь сделать, что-то в корне не так. Двоичные значения с плавающей точкой не имеют десятичных знаков . Вы не можете осмысленно округлить от одного до заданного числа десятичных знаков, потому что большинство «округлых» десятичных значений просто не могут быть представлены в виде двоичной дроби. Вот почему никогда не следует использовать float или double для обозначения денег.

Так что если вы хотите, чтобы в вашем результате были десятичные знаки, этот результат должен быть либо String (который вы уже получили с DecimalFormat), либо BigDecimal (который имеет метод setScale(), который точно то, что ты хочешь). В противном случае результат не может быть таким, как вы хотите.

Чтение Руководство с плавающей точкой для получения дополнительной информации.

2 голосов
/ 20 февраля 2014

Попробуйте это: 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;
        }
    }
}
1 голос
/ 11 сентября 2013
double TotalPrice=90.98989898898;

  DecimalFormat format_2Places = new DecimalFormat("0.00");

    TotalPrice = Double.valueOf(format_2Places.format(TotalPrice));
1 голос
/ 25 января 2011

Это невозможно в запрошенном виде, поскольку существуют числа с двумя десятичными разрядами, которые не могут быть точно выражены с помощью чисел с плавающей запятой IEEE (например, 1/10 = 0,1 не может быть выражено как Double или Float). Форматирование всегда должно выполняться как последний шаг перед тем, как представить результат пользователю.

Я полагаю, вы спрашиваете, потому что хотите иметь дело с денежными значениями. Нет надежного способа сделать это с числами с плавающей запятой, вы должны подумать о переходе на арифметику с фиксированной запятой. Вероятно, это означает выполнение всех расчетов в «центах» вместо «долларов».

1 голос
/ 25 января 2011

Вы можете попытаться определить новый десятичный формат и использовать его как двойной результат для новой двойной переменной.

Пример, который поможет вам понять, что я только что сказал.

double decimalnumber = 100.2397;
DecimalFormat dnf = new DecimalFormat( "#,###,###,##0.00" );
double roundednumber = new Double(dnf.format(decimalnumber)).doubleValue();
0 голосов
/ 09 апреля 2019

Если вы не хотите использовать 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;
}
0 голосов
/ 18 ноября 2013

Вы можете использовать формат как здесь ,

  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;   
    }
}
...