Frage

Ein 64-Bit-Doppel können ganze Zahl darstellen +/- 2 53 genau

diese Tatsache Da wähle ich für alle meine Typen ein Doppeltyp als eine einzige Art zu verwenden, da meine größte ganze Zahl ist unsigned 32-Bit.

Aber jetzt habe ich diese Pseudo ganze Zahlen zu drucken, aber das Problem ist, sie sind auch mit tatsächlichen Doppeln gemischt.

Wie drucke ich dieses Doppel schön in Java?

I String.format("%f", value) versucht haben, die in der Nähe ist, es sei denn ich eine Menge Nullen für kleine Werte erhalten.

Hier ist ein Beispiel für die Ausgabe von den %f

232.00000000
0.18000000000
1237875192.0
4.5800000000
0.00000000
1.23450000

Was ich will, ist:

232
0.18
1237875192
4.58
0
1.2345

Klar, ich eine Funktion schreiben, kann diese Nullen zu trimmen, aber das ist vielen Leistungsverlust durch String-Manipulation. Kann ich mit einem anderen Format Code besser machen?

Bearbeiten

Die Antworten von Tom E. und Jeremy S. sind nicht akzeptabel, da sie beide willkürlich auf 2 Dezimalstellen runden. Bitte haben Sie Verständnis, das Problem, bevor er antwortet.

EDIT 2

Bitte beachten Sie, dass String.format(format, args...) ist locale-abhängige (siehe Antworten unten).

War es hilfreich?

Lösung

Wenn die Idee ist, ganze Zahlen gespeichert zu drucken, wie verdoppelt, als ob sie ganze Zahlen sind, und ansonsten das Doppel mit der erforderlichen Genauigkeit Mindest drucken:

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

Erzeugt:

232
0.18
1237875192
4.58
0
1.2345

Und verlässt sich nicht auf String-Manipulation.

Andere Tipps

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

Wie in den Kommentaren darauf, dies ist nicht die richtige Antwort auf die ursprüngliche Frage.
Das heißt, es ist eine sehr nützliche Art und Weise ist Zahlen zu formatieren, ohne unnötige nachfolgenden Nullen.

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

Kurz gesagt:

Wenn Sie wollen, um loszuwerden, Nullen und Locale Probleme Hinter, dann sollten Sie verwenden:

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

Erklärung:

Warum andere Antworten haben mich nicht passen:

  • Double.toString() oder System.out.println oder FloatingDecimal.toJavaFormatString verwendet Wissenschaftliche Notation wenn Doppel weniger als 10 ^ -3 oder größer als oder gleich 10 ^ 7

    double myValue = 0.00000021d;
    String.format("%s", myvalue); //output: 2.1E-7
    
  • durch %f unter Verwendung der Standard-Dezimalgenauigkeit 6, sonst kann man es hart codieren, aber es führt zu zusätzlichen Nullen hinzugefügt, wenn Sie weniger Dezimalstellen haben. Beispiel:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); //output: 0.000000210000
    
  • durch setMaximumFractionDigits(0); mit oder %.0f entfernen Sie jede Dezimalgenauigkeit, die für ganze Zahlen / Long-Positionen, aber nicht für Doppel in Ordnung ist

    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
    
  • durch DecimalFormat verwenden, sind Sie lokale abhängig. In Französisch locale ist das Dezimaltrennzeichen ein Komma, nicht ein Punkt:

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

    Mit dem englischen Gebietsschema stellt sicher, dass Sie einen Punkt für Dezimaltrennzeichens erhalten, wo immer Ihr Programm läuft

Warum mit 340 dann für setMaximumFractionDigits?

Zwei Gründe:

  • setMaximumFractionDigits akzeptiert eine ganze Zahl, aber seine Umsetzung ist Ziffern maximal DecimalFormat.DOUBLE_FRACTION_DIGITS erlaubt, die 340
  • entspricht
  • Double.MIN_VALUE = 4.9E-324 so mit 340 Stellen Sie sicher sind, nicht Ihre Doppel und lose Präzision runden

Warum nicht:

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

Dies sollte durch Doppel unterstützt mit den Extremwerten arbeiten. Ausbeuten:

0.12
12
12.144252
0

Meine 2 Cent:

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

Auf meinem Rechner die folgende Funktion ist in etwa 7-mal schneller als die Funktion von JasonD Antwort versehen, da sie vermeidet String.format:

public static String prettyPrint(double d) {
  int i = (int) d;
  return d == i ? String.valueOf(i) : String.valueOf(d);
}

Naw, egal.

Performance Verlust durch String-Manipulation Null ist.

Und hier ist der Code, um das Ende nach %f zu trimmen

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

Bitte beachten Sie, dass String.format(format, args...) ist locale-abhängige , weil es formatiert mit dem Standardgebietsschema des Benutzers, , die wahrscheinlich mit Komma und sogar Räumen innen wie 123 456789 oder 123,456.789 , die nicht genau sein kann, was man erwartet.

Sie können es vorziehen, String.format((Locale)null, format, args...) zu verwenden.

Beispiel:

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

druckt

123456,789000
123456,789000
123456.789000

und das ist, was in den verschiedenen Ländern tun String.format(format, args...).

EDIT Ok, da es eine Diskussion über Formalitäten hat:

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

habe ich ein DoubleFormatter, um effizient eine große Anzahl von Doppelwerten zu einem schönen / vorzeigbar String zu konvertieren:

double horribleNumber = 3598945.141658554548844; 
DoubleFormatter df = new DoubleFormatter(4,6); //4 = MaxInteger, 6 = MaxDecimal
String beautyDisplay = df.format(horribleNumber);
  • Wenn der ganzzahlige Teil von V hat mehr als MaxInteger => V Anzeige in Wissenschaftler Format (1.2345e + 30) Anzeige sonst im normalen Format 124,45678.
  • die MaxDecimal entscheiden Anzahl von Dezimalstellen (trim mit Bank Rundung)

Hier ist der 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();
    }
}

Hinweis: Ich habe 2 Funktionen von GUAVA Bibliothek. Wenn Sie nicht GUAVA verwenden, Code it yourself:

/**
 * 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();
}

Verwenden Sie eine DecimalFormat und setMinimumFractionDigits(0)

Dieser wird der Job gut erledigen, ich weiß, das Thema ist alt, aber ich war mit dem gleichen Problem zu kämpfen, bis ich dazu kam. Ich hoffe, dass jemand es nützlich finden.

    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 für eine minimale Anzahl von Ziffern
  2. Renders # Ziffern
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);
    }
}

Späte Antwort, aber ...

Sie sagten, Sie wählen speichern Sie Ihre Zahlen mit dem Doppel Typ . Ich denke, dies ist die Wurzel des Problems sein könnte, weil es Sie zwingt zu speichern Zahlen in Doppel (und damit die erste Informationen über den Wert der Natur zu verlieren). Was ist Ihre Zahlen in Instanzen der Nummer speichern Klasse (Oberklasse sowohl Doppel- und Integer) und stützen sich auf Polymorphismus das richtige Format jeder Nummer?

, um zu bestimmen

Ich weiß es nicht akzeptabel sein kann, einen ganzen Teil des Codes Refactoring wegen, dass aber es könnte die gewünschte Ausgabe ohne zusätzlichen Code / Gießen / Parsing erzeugen.

Beispiel:

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

}

Wird die folgende Ausgabe:

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

Ich hatte diese Ursache d == (long)d zu verwenden gab mir Verletzung in Sonar-Bericht

Das ist, was ich kam mit:

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

Einfache einzeiler, wirft nur dann, wenn wirklich int müssen

Es gibt zwei Möglichkeiten, es zu erreichen. Erstens, die kürzer (und wahrscheinlich besser) Art und Weise:

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

Und hier ist die länger und wahrscheinlich schlechter Weg:

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

Hier ist eine Antwort, die tatsächlich funktioniert (Kombination verschiedener Antworten hier)

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

Ich weiß, dass dies ein wirklich alter Thread ist .. Aber ich denke, der beste Weg, dies zu tun, ist wie folgt:

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

Ausgabe:

3.456 something
3.456234523452 something
3.45 something
3.0 something

Das einzige Problem ist die letzte, in dem 0,0 nicht entfernt bekommt. Aber wenn Sie in der Lage sind, damit zu leben, dann funktioniert dies am besten. % .2f wird es auf den letzten zwei Dezimalstellen abzurunden. So wird DecimalFormat. Wenn Sie alle Dezimalstellen müssen aber nicht die nachgestellten Nullen dann dies am besten funktioniert.

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

Dies wird die Zeichenfolge, um das Tailing 0-s fallen zu lassen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top