Comment bien formater les nombres flottants en chaîne sans décimal inutile 0?

Un double 64 bits peut représenter un entier +/- 253 exactement

Compte tenu de ce fait, je choisis d'utiliser un type double comme un type unique pour tous mes types, puisque mon plus grand entier est non signé 32 bits.

Mais maintenant je dois imprimer ces pseudo entiers, mais le problème est qu'ils sont également mélangés avec des doubles réels.

Alors, comment puis-je imprimer ces doubles bien en Java?

J'ai essayé String.format("%f", value), ce qui est proche, sauf que je reçois beaucoup de zéros pour les petits valeur.

Voici un exemple de sortie de de %f

232.00000000
0.18000000000
1237875192.0
4.5800000000
0.00000000
1.23450000

Ce que je veux, c'est:

232
0.18
1237875192
4.58
0
1.2345

Bien Sûr, je peux écrire une fonction pour couper ces zéros, mais c'est beaucoup de perte de performance due à la manipulation de chaînes. Puis-je faire mieux avec un autre code de format?

Modifier

Les réponses de Tom E. et Jeremy S. sont inacceptables car ils arrondir arbitrairement à 2 décimales. Veuillez comprendre le problème avant de répondre.

Modifier 2

Veuillez noter que String.format(format, args...) est dépendant de paramètres régionaux (voir les réponses ci-dessous).

414
demandé sur 18446744073709551615 2009-04-01 02:54:29

22 réponses

Si l'idée est d'imprimer des entiers stockés sous forme de doubles comme s'ils étaient des entiers, et sinon d'imprimer les doubles avec la précision minimale nécessaire:

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

Produit:

232
0.18
1237875192
4.58
0
1.2345

Et ne repose pas sur la manipulation de chaînes.

339
répondu JasonD 2014-09-14 19:59:42
new DecimalFormat("#.##").format(1.199); //"1.2"

Comme indiqué dans les commentaires, ce n'est pas la bonne réponse à la question d'origine.
Cela dit, c'est un moyen très utile de formater des nombres sans zéros de fin inutiles.

375
répondu Tom Esterez 2016-05-28 04:22:47
String.format("%.2f", value) ;
217
répondu Jeremy Slade 2012-01-04 00:35:09

En bref:

Si vous voulez vous débarrasser des zéros de fin et des problèmes de paramètres régionaux, vous devez utiliser:

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

Explication:

Pourquoi d'autres réponses ne me convenaient pas:

  • Double.toString() ou System.out.println ou FloatingDecimal.toJavaFormatString utilise des notations scientifiques si un double est inférieur à 10^-3 ou supérieure ou égale à 10^7

    double myValue = 0.00000021d;
    String.format("%s", myvalue); //output: 2.1E-7
    
  • En utilisant %f, la précision décimale par défaut est 6, sinon vous pouvez la coder en dur, mais cela entraîne un supplément zéros ajoutés si vous avez moins de décimales. Exemple:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); //output: 0.000000210000
    
  • En utilisant setMaximumFractionDigits(0); ou %.0f vous supprimez toute précision décimale, ce qui est bien pour les entiers / longs mais pas pour double

    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
    
  • En utilisant DecimalFormat, vous êtes dépendant local. En français, le séparateur décimal est une virgule, Pas un point:

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

    L'utilisation des paramètres régionaux anglais vous permet d'obtenir un point pour le séparateur décimal, partout où votre programme s'exécutera

Pourquoi en utilisant 340 alors pour setMaximumFractionDigits ?

Deux raisons :

  • setMaximumFractionDigits accepte un entier mais son implémentation a un nombre maximum autorisé de {[13] } qui est égal à 340
  • Double.MIN_VALUE = 4.9E-324 donc, avec 340 chiffres, vous êtes sûr de ne pas arrondir votre précision double et lâche
73
répondu JBE 2015-02-09 22:48:11

Pourquoi pas:

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

Cela devrait fonctionner avec les valeurs extrêmes supportées par Double. Rendements:

0.12
12
12.144252
0
21
répondu Valeriu Paloş 2014-10-01 00:53:59

Sur ma machine, la fonction suivante est environ 7 fois plus rapide que la fonction fournie par la réponse de JasonD , car elle évite String.format:

public static String prettyPrint(double d) {
  int i = (int) d;
  return d == i ? String.valueOf(i) : String.valueOf(d);
}
19
répondu Rok Strniša 2017-05-23 11:33:24

Mes 2 cents:

if(n % 1 == 0) {
    return String.format(Locale.US, "%.0f", n));
} else {
    return String.format(Locale.US, "%.1f", n));
}
17
répondu Fernando Gallego 2016-08-05 09:36:45

Non, peu importe.

La perte de Performance due à la manipulation de chaînes est nulle.

Et voici le code pour couper la fin d'après %f

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

    return number.replaceAll("\\.?0*$", "");
}
10
répondu Pyrolistical 2013-02-15 17:13:01

Veuillez noter que String.format(format, args...) est dépendant des paramètres régionaux parce qu'il formate en utilisant les paramètres régionaux par défaut de l'utilisateur, c'est-à-dire, probablement avec des virgules et même des espaces à l'intérieur comme 123 456,789 ou 123,456.789, ce qui n'est peut-être pas exactement ce que vous attendez.

Vous pouvez utiliser String.format((Locale)null, format, args...).

Par exemple

    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));

Imprime

123456,789000
123456,789000
123456.789000

Et c'est ce que String.format(format, args...) fera dans différents pays.

Modifier Ok, car il y a eu un discussion sur les formalités:

    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;
}
4
répondu 18446744073709551615 2015-03-16 08:02:21

J'ai fait un DoubleFormatter pour convertir efficacement un grand nombre de valeurs doubles en une chaîne agréable / présentable:

double horribleNumber = 3598945.141658554548844; 
DoubleFormatter df = new DoubleFormatter(4,6); //4 = MaxInteger, 6 = MaxDecimal
String beautyDisplay = df.format(horribleNumber);
  • Si la partie entière de V a plus de MaxInteger = > afficher V au format scientifique (1.2345 e + 30) sinon, afficher au format normal 124.45678.
  • le MaxDecimal décide des nombres de chiffres décimaux (trim avec l'arrondi du banquier)

Voici le code:

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;

/**
 * Convert a double to a beautiful String (US-local):
 * 
 * double horribleNumber = 3598945.141658554548844; 
 * DoubleFormatter df = new DoubleFormatter(4,6);
 * String beautyDisplay = df.format(horribleNumber);
 * String beautyLabel = df.formatHtml(horribleNumber);
 * 
 * Manipulate 3 instances of NumberFormat to efficiently format a great number of double values.
 * (avoid to create an object NumberFormat each call of format()).
 * 
 * 3 instances of NumberFormat will be reused to format a value v:
 * 
 * if v < EXP_DOWN, uses nfBelow
 * if EXP_DOWN <= v <= EXP_UP, uses nfNormal
 * if EXP_UP < v, uses nfAbove
 * 
 * nfBelow, nfNormal and nfAbove will be generated base on the precision_ parameter.
 * 
 * @author: DUONG Phu-Hiep
 */
public class DoubleFormatter
{
    private static final double EXP_DOWN = 1.e-3;
    private double EXP_UP; // always = 10^maxInteger
    private int maxInteger_;
    private int maxFraction_;
    private NumberFormat nfBelow_; 
    private NumberFormat nfNormal_;
    private NumberFormat nfAbove_;

    private enum NumberFormatKind {Below, Normal, Above}

    public DoubleFormatter(int maxInteger, int maxFraction){
        setPrecision(maxInteger, maxFraction);
    }

    public void setPrecision(int maxInteger, int maxFraction){
        Preconditions.checkArgument(maxFraction>=0);
        Preconditions.checkArgument(maxInteger>0 && maxInteger<17);

        if (maxFraction == maxFraction_ && maxInteger_ == maxInteger) {
            return;
        }

        maxFraction_ = maxFraction;
        maxInteger_ = maxInteger;
        EXP_UP =  Math.pow(10, maxInteger);
        nfBelow_ = createNumberFormat(NumberFormatKind.Below);
        nfNormal_ = createNumberFormat(NumberFormatKind.Normal);
        nfAbove_ = createNumberFormat(NumberFormatKind.Above);
    }

    private NumberFormat createNumberFormat(NumberFormatKind kind) {
        final String sharpByPrecision = Strings.repeat("#", maxFraction_); //if you do not use Guava library, replace with createSharp(precision);
        NumberFormat f = NumberFormat.getInstance(Locale.US);

        //Apply banker's rounding:  this is the rounding mode that statistically minimizes cumulative error when applied repeatedly over a sequence of calculations
        f.setRoundingMode(RoundingMode.HALF_EVEN);

        if (f instanceof DecimalFormat) {
            DecimalFormat df = (DecimalFormat) f;
            DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();

            //set group separator to space instead of comma

            //dfs.setGroupingSeparator(' ');

            //set Exponent symbol to minus 'e' instead of 'E'
            if (kind == NumberFormatKind.Above) {
                dfs.setExponentSeparator("e+"); //force to display the positive sign in the exponent part
            } else {
                dfs.setExponentSeparator("e");
            }

            df.setDecimalFormatSymbols(dfs);

            //use exponent format if v is out side of [EXP_DOWN,EXP_UP]

            if (kind == NumberFormatKind.Normal) {
                if (maxFraction_ == 0) {
                    df.applyPattern("#,##0");
                } else {
                    df.applyPattern("#,##0."+sharpByPrecision);
                }
            } else {
                if (maxFraction_ == 0) {
                    df.applyPattern("0E0");
                } else {
                    df.applyPattern("0."+sharpByPrecision+"E0");
                }
            }
        }
        return f;
    } 

    public String format(double v) {
        if (Double.isNaN(v)) {
            return "-";
        }
        if (v==0) {
            return "0"; 
        }
        final double absv = Math.abs(v);

        if (absv<EXP_DOWN) {
            return nfBelow_.format(v);
        }

        if (absv>EXP_UP) {
            return nfAbove_.format(v);
        }

        return nfNormal_.format(v);
    }

    /**
     * format and higlight the important part (integer part & exponent part) 
     */
    public String formatHtml(double v) {
        if (Double.isNaN(v)) {
            return "-";
        }
        return htmlize(format(v));
    }

    /**
     * This is the base alogrithm: create a instance of NumberFormat for the value, then format it. It should
     * not be used to format a great numbers of value 
     * 
     * We will never use this methode, it is here only to understanding the Algo principal:
     * 
     * format v to string. precision_ is numbers of digits after decimal. 
     * if EXP_DOWN <= abs(v) <= EXP_UP, display the normal format: 124.45678
     * otherwise display scientist format with: 1.2345e+30 
     * 
     * pre-condition: precision >= 1
     */
    @Deprecated
    public String formatInefficient(double v) {

        final String sharpByPrecision = Strings.repeat("#", maxFraction_); //if you do not use Guava library, replace with createSharp(precision);

        final double absv = Math.abs(v);

        NumberFormat f = NumberFormat.getInstance(Locale.US);

        //Apply banker's rounding:  this is the rounding mode that statistically minimizes cumulative error when applied repeatedly over a sequence of calculations
        f.setRoundingMode(RoundingMode.HALF_EVEN);

        if (f instanceof DecimalFormat) {
            DecimalFormat df = (DecimalFormat) f;
            DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();

            //set group separator to space instead of comma

            dfs.setGroupingSeparator(' ');

            //set Exponent symbol to minus 'e' instead of 'E'

            if (absv>EXP_UP) {
                dfs.setExponentSeparator("e+"); //force to display the positive sign in the exponent part
            } else {
                dfs.setExponentSeparator("e");
            }
            df.setDecimalFormatSymbols(dfs);

            //use exponent format if v is out side of [EXP_DOWN,EXP_UP]

            if (absv<EXP_DOWN || absv>EXP_UP) {
                df.applyPattern("0."+sharpByPrecision+"E0");
            } else {
                df.applyPattern("#,##0."+sharpByPrecision);
            }
        }
        return f.format(v);
    }

    /**
     * Convert "3.1416e+12" to "<b>3</b>.1416e<b>+12</b>"
     * It is a html format of a number which highlight the integer and exponent part
     */
    private static String htmlize(String s) {
        StringBuilder resu = new StringBuilder("<b>");
        int p1 = s.indexOf('.');

        if (p1>0) {
            resu.append(s.substring(0, p1));
            resu.append("</b>");
        } else {
            p1 = 0;
        }

        int p2 = s.lastIndexOf('e');
        if (p2>0) {
            resu.append(s.substring(p1, p2));
            resu.append("<b>");
            resu.append(s.substring(p2, s.length()));
            resu.append("</b>");
        } else {
            resu.append(s.substring(p1, s.length()));
            if (p1==0){
                resu.append("</b>");
            }
        }
        return resu.toString();
    }
}

Note: j'ai utilisé 2 fonctions de la bibliothèque goyave. Si vous n'utilisez pas de goyave, coder vous-même:

/**
 * Equivalent to Strings.repeat("#", n) of the Guava library: 
 */
private static String createSharp(int n) {
    StringBuilder sb = new StringBuilder(); 
    for (int i=0;i<n;i++) {
        sb.append('#');
    }
    return sb.toString();
}
4
répondu Hiep 2015-08-21 13:03:51
if (d == Math.floor(d)) {
    return String.format("%.0f", d);
} else {
    return Double.toString(d);
}
4
répondu fop6316 2016-07-29 10:33:07
String s = String.valueof("your int variable");
while (g.endsWith("0") && g.contains(".")) {
    g = g.substring(0, g.length() - 1);
    if (g.endsWith("."))
    {
        g = g.substring(0, g.length() - 1);
    }
}
2
répondu kamal 2013-05-22 20:09:42

Celui - ci fera bien le travail, je sais que le sujet est vieux, mais je luttais avec le même problème jusqu'à ce que j'arrive à cela. J'espère que quelqu'un la trouver utile.

    public static String removeZero(double number) {
        DecimalFormat format = new DecimalFormat("#.###########");
        return format.format(number);
    }
2
répondu Bialy 2016-09-10 07:09:56
new DecimalFormat("00.#").format(20.236)
//out =20.2

new DecimalFormat("00.#").format(2.236)
//out =02.2
  1. 0 pour le nombre minimum de chiffres
  2. Rend # chiffres
2
répondu Hossein Hajizadeh 2017-07-15 04:46:19

Réponse Tardive mais...

Vous avez dit que vous Choisissez pour stocker vos numéros avec le Double type . Je pense que cela pourrait être la racine du problème car cela vous oblige à stocker entiers en doubles (et donc perdre les informations initiales sur la nature de la valeur). Qu'en est-il de stocker vos nombres dans les instances de la classe Number (superclasse de Double et D'entier) et de compter sur le polymorphisme pour déterminer le format correct de chaque nombre ?

Je sais qu'il peut ne pas être acceptable de refactoriser une partie entière de votre code à cause de cela, mais cela pourrait produire la sortie désirée sans code/casting/analyse supplémentaire.

Exemple:

import java.util.ArrayList;
import java.util.List;

public class UseMixedNumbers {

    public static void main(String[] args) {
        List<Number> listNumbers = new ArrayList<Number>();

        listNumbers.add(232);
        listNumbers.add(0.18);
        listNumbers.add(1237875192);
        listNumbers.add(4.58);
        listNumbers.add(0);
        listNumbers.add(1.2345);

        for (Number number : listNumbers) {
            System.out.println(number);
        }
    }

}

Produira la sortie suivante:

232
0.18
1237875192
4.58
0
1.2345
1
répondu Spotted 2015-04-23 08:32:54

Utiliser DecimalFormat et setMinimumFractionDigits(0)

1
répondu vlazzle 2017-10-10 19:59:21

Voici deux façons d'y parvenir. Tout d'abord, la manière la plus courte (et probablement la meilleure):

public static String formatFloatToString(final float f)
  {
  final int i=(int)f;
  if(f==i)
    return Integer.toString(i);
  return Float.toString(f);
  }

Et voici la façon la plus longue et probablement la pire:

public static String formatFloatToString(final float f)
  {
  final String s=Float.toString(f);
  int dotPos=-1;
  for(int i=0;i<s.length();++i)
    if(s.charAt(i)=='.')
      {
      dotPos=i;
      break;
      }
  if(dotPos==-1)
    return s;
  int end=dotPos;
  for(int i=dotPos+1;i<s.length();++i)
    {
    final char c=s.charAt(i);
    if(c!='0')
      end=i+1;
    }
  final String result=s.substring(0,end);
  return result;
  }
0
répondu android developer 2015-08-21 14:12:03
public static String fmt(double d) {
    String val = Double.toString(d);
    String[] valArray = val.split("\\.");
    long valLong = 0;
    if(valArray.length == 2){
        valLong = Long.parseLong(valArray[1]);
    }
    if (valLong == 0)
        return String.format("%d", (long) d);
    else
        return String.format("%s", d);
}

J'ai dû utiliser cette cause {[1] } me donnait une violation dans le rapport sonar

0
répondu ShAkKiR 2017-07-25 11:45:23

C'est ce que j'ai trouvé:

  private static String format(final double dbl) {
    return dbl % 1 != 0 ? String.valueOf(dbl) : String.valueOf((int) dbl);
  }

Simple une doublure, seulement jette à int si vraiment besoin de

0
répondu keisar 2018-04-11 17:45:13

Voici une réponse qui fonctionne réellement (combinaison de différentes réponses ici)

public static String removeTrailingZeros(double f)
{
    if(f == (int)f) {
        return String.format("%d", (int)f);
    }
    return String.format("%f", f).replaceAll("0*$", "");
}
-1
répondu Martin Klosi 2013-05-23 18:41:32

Je sais que c'est un très vieux fil.. Mais je pense que la meilleure façon de le faire est comme ci-dessous:

public class Test {

    public static void main(String args[]){
        System.out.println(String.format("%s something",new Double(3.456)));
        System.out.println(String.format("%s something",new Double(3.456234523452)));
        System.out.println(String.format("%s something",new Double(3.45)));
        System.out.println(String.format("%s something",new Double(3)));
    }
}

Sortie:

3.456 something
3.456234523452 something
3.45 something
3.0 something

Le seul problème est Le dernier où .0 n'est pas supprimé. Mais si vous êtes capable de vivre avec cela, cela fonctionne mieux. %.2f arrondira aux 2 derniers chiffres décimaux. Ainsi sera DecimalFormat. Si vous avez besoin de toutes les décimales mais pas des zéros de fin, cela fonctionne mieux.

-2
répondu sethu 2013-01-14 03:46:28
String s = "1.210000";
while (s.endsWith("0")){
    s = (s.substring(0, s.length() - 1));
}

Cela rendra la chaîne pour laisser tomber les 0-s.

-8
répondu Kadi 2011-10-26 12:39:25