напечатать число с 2 цифрами, но округлить с точностью до 6 цифр

Для получения строки ровно с двумя цифрами после «.» Я могу сделать что-то вроде:

        DecimalFormat df = (DecimalFormat)DecimalFormat.getInstance(Locale.US);
        df.applyPattern("0.00");
        df.setRoundingMode(RoundingMode.HALF_UP);
        String output = df.format(value);

Когда у меня есть число, такое как 828.054999999702d, он отформатирует его до 828,05, что пока правильно, поскольку следующая цифра говорит «4», и оно округлит это до нуля.

Но что, если мне нужно сохранить большую точность цифр, просто не хочу их показывать?

Что я быстро создал, так это рабочий код:

        double prettyValue = value;
        prettyValue = Math.round(prettyValue * 1000000d) / 1000000d;
        prettyValue = Math.round(prettyValue * 100000d) / 100000d;
        prettyValue = Math.round(prettyValue * 10000d) / 10000d;
        prettyValue = Math.round(prettyValue * 1000d) / 1000d;
        prettyValue = Math.round(prettyValue * 100d) / 100d; 
        DecimalFormat df = (DecimalFormat)DecimalFormat.getInstance(Locale.US);
        df.applyPattern("0.00");
        df.setRoundingMode(RoundingMode.HALF_UP);
        String output = df.format(prettyValue);

Это будет округлять 6-е, 5-е, 4-е, 3-е, а затем и второе место, NumberFormat не нужно будет ничего делать, а просто печатать 2 оставшиеся цифры, после чего будут нули.

Но я думаю, что должно быть уже нестандартное округление, которого я просто не вижу. Попытка сделать то же самое с BigDecimals приводит к той же проблеме для меня.

В результате я хочу получить 828.054999999702, округленное до 828.06.


person Jens    schedule 09.02.2017    source источник
comment
Попробуйте округлить в меньшую сторону при форматировании вывода.   -  person Thomas    schedule 09.02.2017
comment
Что означает что, если мне нужно сохранить большую точность цифр, просто я не хочу это показывать?? Какое отношение форматирование для отображения имеет к сохранению точности? Если ваш форматированный текст является вашим сохранением, то вы должны показать все цифры, необходимые для сохранения. Если в противном случае значение сохраняется, в чем проблема? Я запутался.   -  person Andreas    schedule 09.02.2017


Ответы (2)


Я не уверен, что полностью понял ваш вопрос, поэтому позвольте мне резюмировать:

  • У вас есть некоторое значение double с потенциально более чем 6 цифрами значащей дроби.
  • Вы хотите округлить это значение до 6 дробных цифр и использовать режим HALF_UP.
  • Вы хотите отображать только первые 2 цифры дроби (я не понимаю, почему, но не буду спрашивать).

В этом случае я бы посоветовал вам сначала использовать BigDecimal для округления, иначе вы можете получить ошибки точности:

double value = 1.23456789;
BigDecimal rounded = BigDecimal.valueOf( value ).setScale(6, RoundingMode.HALF_UP);

Это должно привести к значению 1.234568.

Затем используйте NumberFormat, как и вы, но всегда округляйте в меньшую сторону:

DecimalFormat df = (DecimalFormat)DecimalFormat.getInstance(Locale.US);
df.applyPattern("#.##");
df.setRoundingMode(RoundingMode.DOWN);
String output = df.format( rounded );

Это должно привести к 1.23.

С вашим входным значением 4.23499999999235 вы получите 4.235000 (округленное до 6 цифр) и 4.23.

Правка: мне неизвестен какой-либо режим округления, который округляет 4.23499999999235 до 4.24, но вы сможете добиться этого, объединив несколько вызовов setScale():

BigDecimal rounded = BigDecimal.valueOf( value );
for( int digit = 6; digit >= 2; digit--) {
  rounded = rounded .setScale( digit, RoundingMode.HALF_UP );
}

Это должно применить округление до дробной цифры 6, затем 5 и т. д. и, наконец, округление до 4.24. Я все еще не уверен, что это правильный способ округления, но вы знаете свои требования лучше, чем я :)

person Thomas    schedule 09.02.2017
comment
Кажется, это правильная идея. Но мне все равно нужно будет использовать HALF_UP. Тогда в результате получится 4,24, как я и хотел. Я уточнил это, отредактировав вопрос, также используя другой номер (реальный пример из отладки). - person Jens; 09.02.2017
comment
@Jens, возможно, вы захотите еще раз отредактировать свой вопрос, так как 828.xx в любом случае не округляется до 4.23;) - person Thomas; 10.02.2017
comment
@Jens, посмотрите мое редактирование по крайней мере для одного способа округления, как вы описали. - person Thomas; 10.02.2017
comment
Это именно то, что я сделал в своем вопросе, округлив несколько раз. Но вы помещаете его в цикл for вместо 5 строк, и нет лучшего ответа, поэтому я поставил галочку на этом. Я надеялся, что для этого есть готовое решение, но, возможно, мне нужна для этого математическая библиотека, либо я, либо сторонняя. :) - person Jens; 13.02.2017
comment
@Jens Проблема может заключаться в том, что нормальный режим округления просто включает просмотр следующей цифры, т. Е. При округлении 4.234999 до 2 цифр дроби будет учитываться только третья цифра дроби (4). Таким образом, большинство математических библиотек (а также встроенные функции) содержат только этот метод. - person Thomas; 13.02.2017

Учитывая, что вы выводите это в строку, почему бы не использовать

String output = String.format(java.util.Locale.US,"%.2f", doubleValue);

вместо всех вещей DecimalFormat? Это оставит doubleValue в качестве исходного значения, сохраняя точность.

person igoldthwaite    schedule 09.02.2017
comment
Даже если это укоротит мой пример кода, это ничего не изменит. Вывод String будет содержать число, которое не округлено с точностью более 2 цифр. Строковый формат будет просто смотреть на позицию 3 и округлять эти 4 вместо того, чтобы рассматривать все эти 9999. - person Jens; 09.02.2017
comment
Итак, вы хотите, чтобы 4,2349999 округлилось до 4,24? Похоже, вы просто неправильно округляете. В противном случае я бы сделал то же, что и вы, и округлял от большего числа к меньшему, пока не достигну 2. - person igoldthwaite; 09.02.2017
comment
Я думаю, что это не неправильное округление. Например, финансовые системы часто ограничивают расчет всего с точностью до 6 цифр, но затем отображают только 2 цифры. Но для финансов вы также используете BigDecimal. - person Jens; 09.02.2017