Come posso stampare un doppio valore senza notazione scientifica usando Java?


222

Voglio stampare un doppio valore in Java senza modulo esponenziale.

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

Essa mostra questa E notazione: 1.2345678E7.

Voglio che lo stampi in questo modo: 12345678

Qual è il modo migliore per impedirlo?

Risposte:


116

Puoi usare printf()con %f:

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

Questo stamperà dexp: 12345678.000000. Se non si desidera la parte frazionaria, utilizzare

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

Questo utilizza il linguaggio dell'identificatore di formato spiegato nella documentazione .

Il toString()formato predefinito utilizzato nel codice originale è indicato qui .


1
ma ha mostrato dexp: 12345681.000000quale valore è sbagliato. E in realtà dopo, voglio visualizzarlo sulla mia pagina web dove viene visualizzato in questo modo. 1.2345678E7Esiste comunque un modo per memorizzarlo in un doppio like 12345678e in qualsiasi altro modo?
Cattivissimo

1
@despicable: è possibile che tu stia guardando la vecchia versione incompleta della risposta. Prova a ricaricare la pagina. Dovrebbe esserci un paragrafo su %.0f.
NPE,

@despicable potresti memorizzare dexp come int in modo da poterlo usare facilmente in entrambi i modi
Giustino

10
TROVA IL NUMERO
Confondi il

6
%.0fcompleta il numero. C'è un modo per scartare gli zeri finali?
NurShomik,

239

Java impedisce la notazione E in doppio:

Cinque modi diversi per convertire un doppio in un numero normale:

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

Questo programma stampa:

2.1E-7
.00000021
0.000000210
0.000000210000000000000001085015324114868562332958390470594167709350585
0.000000210000

Che hanno tutti lo stesso valore.

Protip: se sei confuso sul perché quelle cifre casuali appaiono oltre una certa soglia nel doppio valore, questo video spiega: computerphile perché 0.1+ è 0.2uguale 0.30000000000001?

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


Grazie mille per la risposta e soprattutto per il suggerimento. Quel video ha risolto la mia confusione.
AnujDeo,

97

In breve:

Se vuoi sbarazzarti degli zeri finali e dei problemi di Locale, allora dovresti usare:

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

Spiegazione:

Perché altre risposte non mi andavano bene:

  • Double.toString()o System.out.printlno FloatingDecimal.toJavaFormatStringusa notazioni scientifiche se double è inferiore a 10 ^ -3 o maggiore o uguale a 10 ^ 7
  • Usando %f, la precisione decimale predefinita è 6, altrimenti è possibile codificarla, ma si ottengono ulteriori zeri aggiunti se si hanno meno decimali. Esempio:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); // Output: 0.000000210000
  • Usando setMaximumFractionDigits(0);o %.0frimuovendo qualsiasi precisione decimale, che va bene per numeri interi / long, ma non per il doppio:

    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
  • Usando DecimalFormat, sei locale dipendente. Nelle impostazioni locali francesi, il separatore decimale è una virgola, non un punto:

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

    L'uso della localizzazione INGLESE ti assicura di ottenere un punto per il separatore decimale, ovunque il tuo programma verrà eseguito.

Perché usare 340 allora per setMaximumFractionDigits?

Due motivi:

  • setMaximumFractionDigitsaccetta un numero intero, ma la sua implementazione ha un numero massimo consentito di DecimalFormat.DOUBLE_FRACTION_DIGITScui uguale a 340
  • Double.MIN_VALUE = 4.9E-324 quindi con 340 cifre sei sicuro di non arrotondare il doppio e perdere precisione.

Qual è la tua opinione new BigDecimal(myvalue).toPlainString()dalla descrizione a docs.oracle.com/javase/7/docs/api/java/math/… ), non è immediatamente ovvio come si comporta quando vengono dati diversi tipi di numeri, ma elimina la notazione scientifica .
Derek Mahar,

4
new BigDecimal(0.00000021d).toPlainString()uscita 0.0000002100000000000000010850153241148685623329583904705941677093505859375che non è quello che ti aspetteresti ...
JBE

qualche idea su come usare la risposta in scala? probabilmente è una questione di importazioni appropriate ma sono nuovo qui.
jangorecki,

BigDecimal.valueOf(0.00000021d).toPlainString()funziona anche (usa il costruttore String di BigDecimal ecco perché)
marco

27

Puoi provarlo con DecimalFormat. Con questa classe sei molto flessibile nell'analisi dei tuoi numeri.
È possibile impostare esattamente il modello che si desidera utilizzare.
Nel tuo caso ad esempio:

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

16

Ho un'altra soluzione che coinvolge toPlainString () di BigDecimal, ma questa volta usando String-constructor, che è raccomandato in javadoc:

questo costruttore è compatibile con i valori restituiti da Float.toString e Double.toString. Questo è generalmente il modo preferito per convertire un float o un double in un BigDecimal, poiché non risente dell'imprevedibilità del costruttore BigDecimal (doppio).

Sembra così nella sua forma più breve:

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

Prima di Java 8, questo risulta in "0,0" per qualsiasi doppio a valore zero, quindi è necessario aggiungere:

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

NaN e valori infiniti devono essere controllati in più.

Il risultato finale di tutte queste considerazioni:

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

Questo può anche essere copiato / incollato per funzionare bene con Float.


2
Ho letto innumerevoli schemi per convertire un doppio valore in una stringa e questo è il migliore: breve, semplice, configurabile.
Paul,

Ottima soluzione, mi ha davvero aiutato a convertire i doppi valori in String ed evitare la notazione scientifica. Grazie!
pleft

Perché d.doubleValue() == 0invece di d == 0?
Alexei Fando,

Perché evita l'auto-unboxing, che mi piace di più in quella situazione, ma le opinioni possono ovviamente differire su questo. Se sei su Java 8 (9 sarà probabilmente lo stesso), puoi tralasciare del tutto quelle 2 righe.
Manuel,

Appena provato con Java 9, anche queste 2 righe possono essere lasciate fuori su 9.
Manuel,

8

Funzionerà finché il tuo numero è un numero intero:

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

Se la doppia variabile ha precisione dopo il punto decimale, la troncerà.


4

Avevo bisogno di convertire alcuni valori double in currency e ho scoperto che la maggior parte delle soluzioni erano OK, ma non per me.

Alla DecimalFormatfine è stato il modo per me, quindi ecco cosa ho fatto:

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

Come puoi vedere, se il numero è naturale ottengo - diciamo - 20000000 invece di 2E7 (ecc.) - senza alcun punto decimale.

E se è decimale, ottengo solo due cifre decimali.


4

Il compilatore Java / Kotlin converte qualsiasi valore maggiore di 9999999 (maggiore o uguale a 10 milioni) in notazione scientifica, ad es. Notazione di Eilion .

Es .: 12345678 viene convertito in 1.2345678E7

Utilizzare questo codice per evitare la conversione automatica in notazione scientifica:

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

Il seguente codice rileva se il numero fornito è presentato in notazione scientifica. In tal caso, viene rappresentato nella presentazione normale con un massimo di "25" cifre.

 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

Penso che tutti abbiano avuto l'idea giusta, ma tutte le risposte non sono state semplici. Vedo che questo è un pezzo di codice molto utile. Ecco un frammento di ciò che funzionerà:

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

il ".8" è dove si imposta il numero di cifre decimali che si desidera mostrare.

Sto usando Eclipse e non ha funzionato.

Spero sia stato utile. Gradirò ogni feedback!


1

Ho avuto lo stesso problema nel mio codice di produzione quando lo usavo come input di stringa per una funzione math.Eval () che accetta una stringa come "x + 20/50"

Ho guardato centinaia di articoli ... Alla fine sono andato con questo a causa della velocità. E poiché la funzione Eval stava per riconvertirlo nel suo formato numerico alla fine e math.Eval () non supportava l'E-07 finale che altri metodi restituivano, e qualsiasi cosa oltre 5 dp era comunque troppi dettagli per la mia applicazione .

Questo è ora utilizzato nel codice di produzione per un'applicazione che ha oltre 1.000 utenti ...

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

s display as:  0.00021

1

Potrebbe trattarsi di una tangente .... ma se devi inserire un valore numerico come numero intero (che è troppo grande per essere un numero intero) in un serializzatore (JSON, ecc.), Allora probabilmente vuoi "BigInterger"

Esempio: value è una stringa - 7515904334

Dobbiamo rappresentarlo come un numero in un messaggio Json: {"contact_phone": "800220-3333", "servicer_id": 7515904334, "servicer_name": "SOME CORPORATION"}

Non possiamo stamparlo o otterremo questo: {"contact_phone": "800220-3333", "servicer_id": "7515904334", "servicer_name": "SOME CORPORATION"}

L'aggiunta del valore al nodo in questo modo produce il risultato desiderato: BigInteger.valueOf (Long.parseLong (value, 10))

Non sono sicuro che questo sia davvero in tema, ma poiché questa domanda è stata il mio miglior successo quando ho cercato la mia soluzione, ho pensato di condividere qui a beneficio di altri, mentimi, che cercano male. : D


-1

Per i valori interi rappresentati da a double, è possibile utilizzare questo codice, che è molto più veloce delle altre soluzioni.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.