Wie drucke ich einen doppelten Wert ohne wissenschaftliche Notation mit Java?


222

Ich möchte einen doppelten Wert in Java ohne Exponentialform drucken.

double dexp = 12345678;
System.out.println("dexp: "+dexp);

Es zeigt diese E-Notation : 1.2345678E7.

Ich möchte, dass es so gedruckt wird: 12345678

Was ist der beste Weg, um dies zu verhindern?

Antworten:


116

Sie könnten verwenden printf()mit %f:

double dexp = 12345678;
System.out.printf("dexp: %f\n", dexp);

Dies wird gedruckt dexp: 12345678.000000. Wenn Sie den Bruchteil nicht möchten, verwenden Sie

System.out.printf("dexp: %.0f\n", dexp);

Hierbei wird die in der Dokumentation erläuterte Formatspezifizierersprache verwendet .

Das toString()in Ihrem Originalcode verwendete Standardformat ist hier angegeben .


1
aber es hat gezeigt, dexp: 12345681.000000welcher Wert falsch ist. Und tatsächlich möchte ich ihn danach auf meiner Webseite anzeigen, wo er so angezeigt wird. 1.2345678E7Gibt es sowieso einen Ort, über den ich ihn in beliebiger doppelter 12345678und anderer Weise speichern kann ?
Verächtlich

1
@despicable: Möglicherweise haben Sie sich die alte, unvollständige Version der Antwort angesehen. Versuchen Sie, die Seite neu zu laden. Es sollte einen Absatz über geben %.0f.
NPE

@despicable Sie könnten Dexp als Int speichern, so dass Sie es leicht in beide Richtungen verwenden können
Justin

10
IT abrundet DIE ZAHL
Verwirren

6
%.0frundet die Zahl ab. Gibt es eine Möglichkeit, die nachgestellten Nullen einfach zu verwerfen?
NurShomik

239

Java verhindert die E-Notation im Doppelpack:

Fünf verschiedene Möglichkeiten, ein Double in eine normale Zahl umzuwandeln:

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class Runner {
    public static void main(String[] args) {
        double myvalue = 0.00000021d;

        //Option 1 Print bare double.
        System.out.println(myvalue);

        //Option2, use decimalFormat.
        DecimalFormat df = new DecimalFormat("#");
        df.setMaximumFractionDigits(8);
        System.out.println(df.format(myvalue));

        //Option 3, use printf.
        System.out.printf("%.9f", myvalue);
        System.out.println();

        //Option 4, convert toBigDecimal and ask for toPlainString().
        System.out.print(new BigDecimal(myvalue).toPlainString());
        System.out.println();

        //Option 5, String.format 
        System.out.println(String.format("%.12f", myvalue));
    }
}

Dieses Programm druckt:

2.1E-7
.00000021
0.000000210
0.000000210000000000000001085015324114868562332958390470594167709350585
0.000000210000

Welches sind alle den gleichen Wert.

Protip: Wenn Sie sich nicht sicher sind, warum diese zufälligen Ziffern im doppelten Wert über einem bestimmten Schwellenwert liegen, erklärt dieses Video: Computerphile, warum ist 0.1+ 0.2gleich 0.30000000000001?

http://youtube.com/watch?v=PZRI1IfStY0


Vielen Dank für die Antwort und vor allem den Tipp. Dieses Video hat meine Verwirrung gelöst.
AnujDeo

97

Zusamenfassend:

Wenn Sie nachgestellte Nullen und Gebietsschemaprobleme beseitigen möchten, sollten Sie Folgendes 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

Erläuterung:

Warum andere Antworten nicht zu mir passten:

  • Double.toString()oder System.out.printlnoder FloatingDecimal.toJavaFormatStringverwendet wissenschaftliche Notationen, wenn double kleiner als 10 ^ -3 oder größer oder gleich 10 ^ 7 ist
  • Bei Verwendung %fbeträgt die Standard-Dezimalgenauigkeit 6, andernfalls können Sie sie fest codieren. Wenn Sie jedoch weniger Dezimalstellen haben, werden zusätzliche Nullen hinzugefügt. Beispiel:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); // Output: 0.000000210000
    
  • Durch Verwenden setMaximumFractionDigits(0);oder %.0fEntfernen einer Dezimalgenauigkeit, die für Ganzzahlen / Longs, aber nicht für Double 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 die Verwendung von DecimalFormat sind Sie lokal abhängig. Im französischen Gebietsschema ist das Dezimaltrennzeichen ein Komma, kein Punkt:

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

    Durch die Verwendung des Gebietsschemas ENGLISH wird sichergestellt, dass Sie überall dort, wo Ihr Programm ausgeführt wird, einen Punkt für das Dezimaltrennzeichen erhalten.

Warum dann 340 für setMaximumFractionDigits?

Zwei Gründe:

  • setMaximumFractionDigitsakzeptiert eine Ganzzahl, aber für die Implementierung sind maximal Ziffern zulässig, von DecimalFormat.DOUBLE_FRACTION_DIGITSdenen 340 entspricht
  • Double.MIN_VALUE = 4.9E-324 Mit 340 Stellen können Sie also sicher sein, dass Sie Ihr Doppel nicht runden und an Präzision verlieren.

Was ist Ihre Meinung zu? new BigDecimal(myvalue).toPlainString()Aus der Beschreibung unter docs.oracle.com/javase/7/docs/api/java/math/… ) geht nicht sofort hervor, wie es sich verhält, wenn verschiedene Arten von Zahlen angegeben werden, aber es beseitigt die wissenschaftliche Notation .
Derek Mahar

4
new BigDecimal(0.00000021d).toPlainString()Ausgabe, 0.0000002100000000000000010850153241148685623329583904705941677093505859375die nicht das ist, was Sie erwarten würden ...
JBE

Hast du eine Idee, wie du deine Antwort in Scala verwenden kannst? wahrscheinlich eine Frage angemessener Importe, aber ich bin neu hier.
Jangorecki

BigDecimal.valueOf(0.00000021d).toPlainString()funktioniert auch (es verwendet den String-Konstruktor von BigDecimal, deshalb)
marco

27

Sie können es mit versuchen DecimalFormat. Mit dieser Klasse können Sie Ihre Zahlen sehr flexibel analysieren.
Sie können genau das Muster einstellen, das Sie verwenden möchten.
In Ihrem Fall zum Beispiel:

double test = 12345678;
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(0);
System.out.println(df.format(test)); //12345678

16

Ich habe eine andere Lösung mit toPlainString () von BigDecimal, aber diesmal mit dem String-Konstruktor, der im Javadoc empfohlen wird:

Dieser Konstruktor ist mit den von Float.toString und Double.toString zurückgegebenen Werten kompatibel. Dies ist im Allgemeinen die bevorzugte Methode zum Konvertieren eines Floats oder Double in ein BigDecimal, da es nicht unter der Unvorhersehbarkeit des BigDecimal (Double) -Konstruktors leidet.

Es sieht in seiner kürzesten Form so aus:

return new BigDecimal(myDouble.toString()).stripTrailingZeros().toPlainString();

Vor Java 8 ergibt dies "0.0" für alle nullwertigen Doubles. Sie müssten also Folgendes hinzufügen:

if (myDouble.doubleValue() == 0)
    return "0";

NaN- und unendliche Werte müssen zusätzlich überprüft werden.

Das Endergebnis all dieser Überlegungen:

public static String doubleToString(Double d) {
    if (d == null)
        return null;
    if (d.isNaN() || d.isInfinite())
        return d.toString();

    // Pre Java 8, a value of 0 would yield "0.0" below
    if (d.doubleValue() == 0)
        return "0";
    return new BigDecimal(d.toString()).stripTrailingZeros().toPlainString();
}

Dies kann auch kopiert / eingefügt werden, um mit Float gut zu funktionieren.


2
Ich habe unzählige Schemata gelesen, um einen doppelten Wert in einen String umzuwandeln, und dies ist das Beste: kurz, unkompliziert, konfigurierbar.
Paul

Tolle Lösung, hat mir wirklich geholfen, doppelte Werte in String umzuwandeln und die wissenschaftliche Notation zu vermeiden. Vielen Dank!
Pleft

Warum d.doubleValue() == 0statt d == 0?
Alexei Fando

Weil es das automatische Entpacken vermeidet, was mir in dieser Situation besser gefällt, aber die Ansichten können sich natürlich unterscheiden. Wenn Sie auf Java 8 sind (9 wird wahrscheinlich gleich sein), können Sie diese 2 Zeilen ganz weglassen.
Manuel

Gerade mit Java 9 versucht, können diese 2 Zeilen auch auf 9 weggelassen werden.
Manuel

8

Dies funktioniert, solange Ihre Nummer eine ganze Nummer ist:

double dnexp = 12345678;
System.out.println("dexp: " + (long)dexp);

Wenn die Doppelvariable nach dem Dezimalpunkt genau ist, wird sie abgeschnitten.


4

Ich musste einige doppelte in Währungswerte umrechnen und stellte fest, dass die meisten Lösungen in Ordnung waren, aber nicht für mich.

Das DecimalFormatwar schließlich der Weg für mich, also habe ich Folgendes getan:

   public String foo(double value) //Got here 6.743240136E7 or something..
    {
        DecimalFormat formatter;

        if(value - (int)value > 0.0)
            formatter = new DecimalFormat("0.00"); // Here you can also deal with rounding if you wish..
        else
            formatter = new DecimalFormat("0");

        return formatter.format(value);
    }

Wie Sie sehen können, erhalte ich, wenn die Zahl natürlich ist, beispielsweise 20000000 anstelle von 2E7 (usw.) ohne Dezimalpunkt.

Und wenn es dezimal ist, bekomme ich nur zwei Dezimalstellen.


4

Der Java / Kotlin-Compiler konvertiert jeden Wert größer als 9999999 (größer oder gleich 10 Millionen) in wissenschaftliche Notation, d. H. Epsilion Notation .

Beispiel: 12345678 wird in 1.2345678E7 konvertiert

Verwenden Sie diesen Code, um eine automatische Konvertierung in wissenschaftliche Notation zu vermeiden:

fun setTotalSalesValue(String total) {
        var valueWithoutEpsilon = total.toBigDecimal()
        /* Set the converted value to your android text view using setText() function */
        salesTextView.setText( valueWithoutEpsilon.toPlainString() )
    }

3

Der folgende Code erkennt, ob die angegebene Nummer in wissenschaftlicher Notation angegeben ist. Wenn ja, wird es in normaler Darstellung mit maximal 25 Ziffern dargestellt.

 static String convertFromScientificNotation(double number) {
    // Check if in scientific notation
    if (String.valueOf(number).toLowerCase().contains("e")) {
        System.out.println("The scientific notation number'"
                + number
                + "' detected, it will be converted to normal representation with 25 maximum fraction digits.");
        NumberFormat formatter = new DecimalFormat();
        formatter.setMaximumFractionDigits(25);
        return formatter.format(number);
    } else
        return String.valueOf(number);
}

1

Ich denke, jeder hatte die richtige Idee, aber alle Antworten waren nicht einfach. Ich kann sehen, dass dies ein sehr nützlicher Code ist. Hier ist ein Ausschnitt dessen, was funktionieren wird:

System.out.println(String.format("%.8f", EnterYourDoubleVariableHere));

das ".8"ist , wo Sie die Anzahl der Dezimalstellen festgelegt würden Sie gerne zeigen.

Ich benutze Eclipse und es hat kein Problem funktioniert.

Hoffe das war hilfreich. Ich würde mich über Feedback freuen!


1

Ich hatte das gleiche Problem in meinem Produktionscode, als ich ihn als Zeichenfolgeneingabe für eine math.Eval () -Funktion verwendete, die eine Zeichenfolge wie "x + 20/50" verwendet.

Ich habe mir Hunderte von Artikeln angesehen ... Am Ende habe ich mich wegen der Geschwindigkeit dafür entschieden. Und weil die Eval-Funktion es irgendwann wieder in ihr eigenes Zahlenformat konvertieren würde und math.Eval () das nachfolgende E-07, das andere Methoden zurückgaben, nicht unterstützte und alles über 5 dp sowieso zu detailliert für meine Anwendung war .

Dies wird jetzt im Produktionscode für eine Anwendung mit mehr als 1.000 Benutzern verwendet ...

double value = 0.0002111d;
String s = Double.toString(((int)(value * 100000.0d))/100000.0d); // Round to 5 dp

s display as:  0.00021

1

Dies mag eine Tangente sein ... aber wenn Sie einen numerischen Wert als Ganzzahl (die zu groß ist, um eine Ganzzahl zu sein) in einen Serializer (JSON usw.) eingeben müssen, möchten Sie wahrscheinlich "BigInterger"

Beispiel: Wert ist eine Zeichenfolge - 7515904334

Wir müssen es als Zahl in einer Json-Nachricht darstellen: {"contact_phone": "800220-3333", "servicer_id": 7515904334, "servicer_name": "SOME CORPORATION"}

Wir können es nicht drucken oder wir bekommen folgendes: {"contact_phone": "800220-3333", "servicer_id": "7515904334", "servicer_name": "SOME CORPORATION"}

Wenn Sie den Wert wie folgt zum Knoten hinzufügen, erhalten Sie das gewünschte Ergebnis: BigInteger.valueOf (Long.parseLong (Wert, 10))

Ich bin mir nicht sicher, ob dies wirklich ein Thema ist, aber da diese Frage mein Top-Hit war, als ich nach meiner Lösung suchte, dachte ich, ich würde sie hier zum Nutzen anderer teilen, lüge mich, die schlecht suchen. : D.


-1

Für ganzzahlige Werte, die durch a dargestellt werden double, können Sie diesen Code verwenden, der viel schneller als die anderen Lösungen ist.

public static String doubleToString(final double d) {
    // check for integer, also see https://stackoverflow.com/a/9898613/868941 and
    // https://github.com/google/guava/blob/master/guava/src/com/google/common/math/DoubleMath.java
    if (isMathematicalInteger(d)) {
        return Long.toString((long)d);
    } else {
        // or use any of the solutions provided by others
        return Double.toString(d);
    }
}

// Java 8+
public static boolean isMathematicalInteger(final double d) {
    return StrictMath.rint(d) == d && Double.isFinite(d);
}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.