Как красиво отформатировать плавающие числа в строку без лишних десятичных 0? - PullRequest
446 голосов
/ 01 апреля 2009

64-битный дубль может представлять целое число +/- 2 53 точно

Учитывая этот факт, я решил использовать двойной тип в качестве единого типа для всех моих типов, так как мое самое большое целое число - 32-разрядное без знака.

Но теперь я должен напечатать эти псевдоцелые числа, но проблема в том, что они также смешиваются с реальными двойными числами.

Итак, как мне правильно напечатать эти двойники на Java?

Я пробовал String.format("%f", value), что близко, за исключением того, что я получаю много конечных нулей для малых значений.

Вот пример выходных данных %f

232.00000000
0.18000000000
1237875192.0
4.5800000000
0.00000000
1.23450000

Что я хочу, это:

232
0.18
1237875192
4.58
0
1.2345

Конечно, я могу написать функцию для обрезки этих нулей, но это большая потеря производительности из-за манипулирования строками. Могу ли я сделать лучше с кодом другого формата?

EDIT

Ответы Тома Э. и Джереми С. неприемлемы, поскольку они оба произвольно округляют до 2 десятичных знаков. Пожалуйста, поймите проблему, прежде чем ответить.

РЕДАКТИРОВАТЬ 2

Обратите внимание, что String.format(format, args...) является в зависимости от региона (см. Ответы ниже).

Ответы [ 22 ]

392 голосов
/ 15 ноября 2010
new DecimalFormat("#.##").format(1.199); //"1.2"

Как указано в комментариях, это не правильный ответ на исходный вопрос.
Тем не менее, это очень полезный способ форматирования чисел без лишних конечных нулей.

362 голосов
/ 02 января 2013

Если идея состоит в том, чтобы напечатать целые числа, хранящиеся в виде двойных чисел, как если бы они были целыми числами, и в противном случае вывести двойные числа с минимально необходимой точностью:

public static String fmt(double d)
{
    if(d == (long) d)
        return String.format("%d",(long)d);
    else
        return String.format("%s",d);
}

Производит:

232
0.18
1237875192
4.58
0
1.2345

И не полагается на манипуляции со строками.

224 голосов
/ 14 августа 2009
String.format("%.2f", value) ;
80 голосов
/ 14 августа 2014

Короче говоря:

Если вы хотите избавиться от конечных нулей и проблем локали, то вам следует использовать:

double myValue = 0.00000021d;

DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340); //340 = DecimalFormat.DOUBLE_FRACTION_DIGITS

System.out.println(df.format(myValue)); //output: 0.00000021

Пояснение:

Почему другие ответы меня не устраивали:

  • Double.toString() или System.out.println или FloatingDecimal.toJavaFormatString использует научные обозначения, если double меньше 10 ^ -3 или больше или равно 10 ^ 7

    double myValue = 0.00000021d;
    String.format("%s", myvalue); //output: 2.1E-7
    
  • при использовании %f десятичная точность по умолчанию равна 6, в противном случае вы можете жестко закодировать ее, но это приведет к добавлению дополнительных нулей, если у вас меньше десятичных знаков. Пример:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); //output: 0.000000210000
    
  • с помощью setMaximumFractionDigits(0); или %.0f вы удаляете любую десятичную точность, которая подходит для целых / длинных, но не для двойной

    double myValue = 0.00000021d;
    System.out.println(String.format("%.0f", myvalue)); //output: 0
    DecimalFormat df = new DecimalFormat("0");
    System.out.println(df.format(myValue)); //output: 0
    
  • при использовании DecimalFormat вы зависите от местных условий. Во французском языке десятичный разделитель - это запятая, а не точка:

    double myValue = 0.00000021d;
    DecimalFormat df = new DecimalFormat("0");
    df.setMaximumFractionDigits(340);
    System.out.println(df.format(myvalue));//output: 0,00000021
    

    Использование английского языка гарантирует, что вы получите точку для десятичного разделителя, где бы ни выполнялась ваша программа

Зачем использовать 340 тогда для setMaximumFractionDigits?

Две причины:

  • setMaximumFractionDigits принимает целое число, но его реализация имеет максимально допустимые цифры DecimalFormat.DOUBLE_FRACTION_DIGITS, что равно 340
  • Double.MIN_VALUE = 4.9E-324 так что с 340 цифрами вы точно не округлите свою двойную и потерянную точность
24 голосов
/ 01 октября 2014

Почему бы и нет:

if (d % 1.0 != 0)
    return String.format("%s", d);
else
    return String.format("%.0f",d);

Это должно работать с экстремальными значениями, поддерживаемыми Double. Урожайность:

0.12
12
12.144252
0
23 голосов
/ 05 августа 2016

Мои 2 цента:

if(n % 1 == 0) {
    return String.format(Locale.US, "%.0f", n));
} else {
    return String.format(Locale.US, "%.1f", n));
}
22 голосов
/ 10 февраля 2014

На моем компьютере следующая функция примерно в 7 раз быстрее, чем функция, предоставляемая ответом JasonD , поскольку она избегает String.format:

public static String prettyPrint(double d) {
  int i = (int) d;
  return d == i ? String.valueOf(i) : String.valueOf(d);
}
11 голосов
/ 01 апреля 2009

Нау, неважно.

Потеря производительности из-за манипуляции со строкой равна нулю.

А вот код для обрезки конца после %f

private static String trimTrailingZeros(String number) {
    if(!number.contains(".")) {
        return number;
    }

    return number.replaceAll("\\.?0*$", "");
}
6 голосов
/ 29 июля 2016
if (d == Math.floor(d)) {
    return String.format("%.0f", d);
} else {
    return Double.toString(d);
}
5 голосов
/ 13 марта 2015

Обратите внимание, что String.format(format, args...) - это в зависимости от локали , поскольку он форматирует с использованием локали пользователя по умолчанию, , то есть, вероятно, с запятыми и даже пробелами внутри как 123 456 789 или 123 456,789 , что может быть не совсем тем, что вы ожидаете.

Вы можете предпочесть использовать String.format((Locale)null, format, args...).

Например,

    double f = 123456.789d;
    System.out.println(String.format(Locale.FRANCE,"%f",f));
    System.out.println(String.format(Locale.GERMANY,"%f",f));
    System.out.println(String.format(Locale.US,"%f",f));

печать

123456,789000
123456,789000
123456.789000

и это то, что String.format(format, args...) будет делать в разных странах.

РЕДАКТИРОВАТЬ Хорошо, так как было обсуждение формальностей:

    res += stripFpZeroes(String.format((Locale) null, (nDigits!=0 ? "%."+nDigits+"f" : "%f"), value));
    ...

protected static String stripFpZeroes(String fpnumber) {
    int n = fpnumber.indexOf('.');
    if (n == -1) {
        return fpnumber;
    }
    if (n < 2) {
        n = 2;
    }
    String s = fpnumber;
    while (s.length() > n && s.endsWith("0")) {
        s = s.substring(0, s.length()-1);
    }
    return s;
}
...