Question

Un double peut représenter entier +/- 2 53 64 bits exactement

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

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

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

Je l'ai essayé String.format("%f", value), qui est proche, sauf que je reçois beaucoup de zéros pour les petites valeurs.

Voici un exemple de sortie de %f de

232.00000000
0.18000000000
1237875192.0
4.5800000000
0.00000000
1.23450000

Ce que je veux 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 String. Puis-je faire mieux avec un autre code de format?

EDIT

Les réponses de Tom E. et Jeremy S. sont inacceptables car ils les deux tours arbitrairement à 2 décimales. S'il vous plaît comprendre le problème avant de répondre.

EDIT 2

S'il vous plaît noter que String.format(format, args...) est dépendant de la localisation (voir les réponses ci-dessous).

Était-ce utile?

La solution

Si l'idée est d'imprimer des entiers stockés en double comme si elles sont des nombres entiers, et par ailleurs imprimer le double avec la précision minimum 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.

Autres conseils

new DecimalFormat("#.##").format(1.199); //"1.2"

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

String.format("%.2f", value) ;

En bref:

Si vous voulez vous débarrasser de fuite des zéros et des problèmes de localisation, 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:

  • Double.toString() ou System.out.println ou FloatingDecimal.toJavaFormatString utilise notation scientifique si la 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 coder en dur, mais il se traduit par des zéros supplémentaires 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 vous %.0f enlever toute précision décimale, ce qui est bien pour les entiers / longs, mais pas pour le 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
    
  • à l'aide DecimalFormat, vous dépendez locale. En environnement local 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
    

    En utilisant les paramètres régionaux anglais fait en sorte que vous obtenez un point pour le séparateur décimal, chaque fois que votre programme sera exécuté

Pourquoi utiliser 340 puis pour setMaximumFractionDigits?

Deux raisons:

  • setMaximumFractionDigits accepte un entier, mais sa mise en œuvre a un chiffre maximum autorisé de DecimalFormat.DOUBLE_FRACTION_DIGITS 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

Pourquoi ne 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 prises en charge par Double. Les rendements:

0.12
12
12.144252
0

Mes 2 cents:

if(n % 1 == 0) {
    return String.format(Locale.US, "%.0f", n));
} else {
    return String.format(Locale.US, "%.1f", n));
}

Sur ma machine, la fonction suivante est environ 7 fois plus rapide que la fonction fournie par réponse 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);
}

Naw, never mind.

perte de performance due à la manipulation chaîne est égale à zéro.

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

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

    return number.replaceAll("\\.?0*$", "");
}
if (d == Math.floor(d)) {
    return String.format("%.0f", d);
} else {
    return Double.toString(d);
}

S'il vous plaît noter que String.format(format, args...) est dépendant de la localisation parce que les formats en utilisant les paramètres régionaux par défaut de l'utilisateur, qui est, sans doute par des virgules et même des espaces à l'intérieur comme 123 456789 ou 123,456.789 , qui peut être pas exactement ce que vous attendez.

Vous pouvez préférer 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));

impressions

123456,789000
123456,789000
123456.789000

et c'est ce qui String.format(format, args...) faire dans les différents pays.

EDIT Ok, car il y a eu une discussion au sujet des 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;
}

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

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 => affichage V au format scientifique (1.2345E + 30) sinon afficher en format normal 124,45678.
  • le MaxDecimal décider le nombre de chiffres décimaux (garniture avec arrondi de 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 goyave, le code 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();
}

Utilisez un DecimalFormat et setMinimumFractionDigits(0)

Celui-ci va faire le travail bien, je sais que le sujet est vieux, mais je luttais avec la même question jusqu'à ce que je suis venu à ce sujet. J'espère que quelqu'un trouve utile.

    public static String removeZero(double number) {
        DecimalFormat format = new DecimalFormat("#.###########");
        return format.format(number);
    }
new DecimalFormat("00.#").format(20.236)
//out =20.2

new DecimalFormat("00.#").format(2.236)
//out =02.2
  1. 0 pour le nombre minimal de chiffres
  2. Renders chiffres #
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);
    }
}

réponse tardive, mais ...

Vous avez dit que vous Sélectionnez pour stocker vos numéros avec le type double . Je pense que cela pourrait être la racine du problème, car il vous oblige à stocker des entiers en double (et donc perdre les premières informations sur la nature de la valeur). Qu'en est-il de stocker vos numéros dans les cas de la Nombre classe (superclasse des deux double et entier) et compter sur le polymorphisme pour déterminer le format correct de chaque numéro?

Je sais qu'il ne peut pas être acceptable pour factoriser toute une partie de votre code en raison de cela, mais il pourrait produire la sortie désirée sans code supplémentaire / casting / analyse syntaxique.

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

Je devais utiliser cette cause d == (long)d me donnait violation dans le rapport sonar

est ce que je suis venu avec:

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

Simple une doublure, ne jette int si vraiment besoin

Voici deux moyens d'y parvenir. Tout d'abord, le chemin le plus court (et probablement mieux):

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 plus long et probablement pire façon:

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

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

public static String removeTrailingZeros(double f)
{
    if(f == (int)f) {
        return String.format("%d", (int)f);
    }
    return String.format("%f", f).replaceAll("0*$", "");
}

Je sais que c'est un fil vraiment vieux .. 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 la dernière où se .0 ne pas enlevé. Mais si vous êtes en mesure de vivre avec ça, alors ce qui fonctionne le mieux. % .2f va arrondir les 2 derniers chiffres décimaux. Il en va de Decimal. Si vous avez besoin de toutes les décimales, mais pas les zéros alors ce qui fonctionne le mieux.

String s = "1.210000";
while (s.endsWith("0")){
    s = (s.substring(0, s.length() - 1));
}

Cela rendra la chaîne à laisser tomber le 0-tailing s.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top