Jak wydrukować podwójną wartość bez notacji naukowej za pomocą Java?


222

Chcę wydrukować podwójną wartość w Javie bez postaci wykładniczej.

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

To pokazuje ten zapis E: 1.2345678E7.

Chcę go wydrukować w ten sposób: 12345678

Jaki jest najlepszy sposób, aby temu zapobiec?

Odpowiedzi:


116

Możesz użyć printf()z %f:

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

To zostanie wydrukowane dexp: 12345678.000000. Jeśli nie chcesz części ułamkowej, użyj

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

Używa to języka specyfikatora formatu wyjaśnionego w dokumentacji .

Domyślny toString()format użyty w oryginalnym kodzie został zapisany tutaj .


1
ale pokazało, dexp: 12345681.000000która zła wartość. A właściwie po tym chcę wyświetlić ją na mojej stronie internetowej, gdzie jest wyświetlana w ten sposób. 1.2345678E7Czy mimo to mogę ją przechowywać w dowolny 12345678sposób?
Despicable

1
@specable: Być może patrzyłeś na starą, niepełną wersję odpowiedzi. Spróbuj ponownie załadować stronę. Powinien być akapit na temat %.0f.
NPE

@specable można przechowywać dexp jako int, dzięki czemu można go łatwo używać na dwa sposoby
Justin

10
TO ROUNDS OFF THE NUMBER
Mylić

6
%.0fzaokrągla liczbę. Czy istnieje sposób, aby po prostu odrzucić końcowe zera?
NurShomik

239

Java zapobiega notacji E podwójnie:

Pięć różnych sposobów konwersji podwójnej liczby na normalną:

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

Ten program drukuje:

2.1E-7
.00000021
0.000000210
0.000000210000000000000001085015324114868562332958390470594167709350585
0.000000210000

Które mają tę samą wartość.

Protip: Jeśli jesteś zdezorientowany, dlaczego te losowe cyfry pojawiają się powyżej pewnego progu w podwójnej wartości, ten film wyjaśnia: komputerowy, dlaczego 0.1+ 0.2równa się 0.30000000000001?

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


Bardzo dziękuję za odpowiedź, a zwłaszcza za wskazówkę. Ten film rozwiązał moje zamieszanie.
AnujDeo

97

W skrócie:

Jeśli chcesz pozbyć się zer i problemów z ustawieniami regionalnymi, powinieneś użyć:

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

Wyjaśnienie:

Dlaczego inne odpowiedzi mi nie pasują:

  • Double.toString()lub System.out.printlnlub FloatingDecimal.toJavaFormatStringwykorzystuje notacji naukowej, gdy podwójne jest mniejsza niż 10 ^ -3 lub większą niż lub równą 10 ^ 7
  • Przy użyciu %fdomyślna dokładność dziesiętna wynosi 6, w przeciwnym razie możesz ją zakodować na stałe, ale powoduje to dodanie dodatkowych zer, jeśli masz mniej miejsc po przecinku. Przykład:

    double myValue = 0.00000021d;
    String.format("%.12f", myvalue); // Output: 0.000000210000
  • Używając setMaximumFractionDigits(0);lub %.0fusuwasz dokładność dziesiętną, co jest dobre dla liczb całkowitych / długich, ale nie dla podwójnej:

    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
  • Korzystając z DecimalFormat, jesteś zależny lokalnie. W języku francuskim separatorem dziesiętnym jest przecinek, a nie kropka:

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

    Korzystanie z ustawień regionalnych w języku ANGIELSKIM zapewnia, że ​​otrzymasz punkt separatora dziesiętnego, niezależnie od miejsca działania programu.

Po co więc używać 340 setMaximumFractionDigits?

Dwa powody:

  • setMaximumFractionDigitsakceptuje liczbę całkowitą, ale jej implementacja ma maksymalną dozwoloną liczbę cyfr, z DecimalFormat.DOUBLE_FRACTION_DIGITSczego 340
  • Double.MIN_VALUE = 4.9E-324 więc z 340 cyframi na pewno nie zaokrąglisz swojej liczby podwójnej i stracisz precyzję.

Jaka jest twoja opinia new BigDecimal(myvalue).toPlainString()Z opisu na docs.oracle.com/javase/7/docs/api/java/math/… ), nie jest od razu oczywiste, jak się zachowuje, gdy podaje się różne typy liczb, ale eliminuje notację naukową .
Derek Mahar

4
new BigDecimal(0.00000021d).toPlainString()wyjście, 0.0000002100000000000000010850153241148685623329583904705941677093505859375które nie jest tym, czego można oczekiwać ...
JBE,

jakiś pomysł, jak wykorzystać swoją odpowiedź w scala? prawdopodobnie kwestia odpowiedniego importu, ale jestem tu nowy.
jangorecki

BigDecimal.valueOf(0.00000021d).toPlainString()również działa (używa konstruktora ciągów BigDecimal, dlatego)
marco

27

Możesz tego spróbować DecimalFormat. Dzięki tej klasie możesz bardzo elastycznie analizować swoje liczby.
Możesz dokładnie ustawić wzór, którego chcesz użyć.
W twoim przypadku na przykład:

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

16

Mam inne rozwiązanie z funkcją toPlainString () BigDecimal, ale tym razem za pomocą konstruktora ciągów, który jest zalecany w javadoc:

ten konstruktor jest zgodny z wartościami zwracanymi przez Float.toString i Double.toString. Jest to ogólnie preferowany sposób konwersji liczby zmiennoprzecinkowej lub podwójnej na BigDecimal, ponieważ nie cierpi z powodu nieprzewidywalności (podwójnego) konstruktora BigDecimal.

Wygląda to tak w najkrótszej formie:

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

W wersjach wcześniejszych niż Java 8 wynikiem tego jest „0.0” dla dowolnych Doubles o zerowej wartości, dlatego należy dodać:

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

NaN i wartości nieskończone należy dodatkowo sprawdzić.

Ostateczny wynik wszystkich tych rozważań:

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

Można to również skopiować / wkleić, aby ładnie współpracować z Float.


2
Przeczytałem niezliczone schematy, aby przekonwertować podwójną wartość na String i jest to najlepsze: krótkie, proste, konfigurowalne.
Paul,

Świetne rozwiązanie, naprawdę pomogło mi przekonwertować podwójne wartości na String i uniknąć notacji naukowej. Dzięki!
pleft

Dlaczego d.doubleValue() == 0zamiast d == 0?
Alexei Fando

Ponieważ pozwala to uniknąć automatycznego rozpakowywania, co w tej sytuacji bardziej mi się podoba, ale widoki mogą się oczywiście różnić. Jeśli jesteś na java 8 (9 prawdopodobnie będzie taki sam), możesz całkowicie pominąć te 2 linie.
Manuel

Właśnie wypróbowałem z java 9, te 2 linie można również pominąć na 9.
Manuel

8

Działa to tak długo, jak długo Twój numer jest liczbą całkowitą:

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

Jeśli podwójna zmienna ma precyzję po przecinku dziesiętnym, zostanie obcięta.


4

Musiałem przekonwertować niektóre wartości podwójne na walutę i stwierdziłem, że większość rozwiązań była OK, ale nie dla mnie.

W DecimalFormatkońcu był dla mnie sposób, więc oto co zrobiłem:

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

Jak widać, jeśli liczba jest naturalna, otrzymuję - powiedzmy - 20000000 zamiast 2E7 (itd.) - bez kropki dziesiętnej.

A jeśli jest dziesiętny, dostaję tylko dwie cyfry dziesiętne.


4

Kompilator Java / Kotlin konwertuje dowolną wartość większą niż 9999999 (większą lub równą 10 milionom) na notację naukową, tj. Notacja Epsilion .

Np .: 12345678 jest konwertowany na 1,2345678E7

Użyj tego kodu, aby uniknąć automatycznej konwersji na notację naukową:

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

Poniższy kod wykrywa, czy podany numer jest prezentowany w notacji naukowej. Jeśli tak, jest reprezentowany w normalnej prezentacji z maksymalnie 25 cyframi.

 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

Myślę, że każdy miał dobry pomysł, ale wszystkie odpowiedzi nie były proste. Widzę, że jest to bardzo przydatny fragment kodu. Oto fragment tego, co zadziała:

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

".8"miejscu można ustawić liczbę miejsc po przecinku chcesz pokazać.

Używam Eclipse i to nie działało bez problemu.

Mam nadzieję, że to było pomocne. Byłbym wdzięczny za wszelkie opinie!


1

Miałem ten sam problem w kodzie produkcyjnym, gdy używałem go jako wejściowego ciągu znaków do funkcji math.Eval (), która pobiera ciąg taki jak „x + 20/50”

Przejrzałem setki artykułów ... W końcu poszedłem z tym ze względu na szybkość. A ponieważ funkcja Eval zamierzała ostatecznie przekonwertować ją z powrotem na własny format liczb, a funkcja mat.Eval () nie obsługiwała końcowego E-07, który zwróciły inne metody, a wszystko powyżej 5 dp było zbyt szczegółowe dla mojej aplikacji .

Jest to teraz używane w kodzie produkcyjnym aplikacji, która ma ponad 1000 użytkowników ...

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

s display as:  0.00021

1

Może to być styczna .... ale jeśli musisz wprowadzić wartość liczbową jako liczbę całkowitą (która jest zbyt duża, aby być liczbą całkowitą) w serializatorze (JSON itp.), Prawdopodobnie prawdopodobnie potrzebujesz „BigInterger”

Przykład: wartość jest łańcuchem - 7515904334

Musimy przedstawić go w postaci liczbowej w komunikacie Jsona: {„contact_phone”: „800220-3333”, „servicer_id”: 7515904334, „servicer_name”: „SOME CORPORATION”}

Nie możemy go wydrukować lub otrzymamy: {„contact_phone”: „800220-3333”, „servicer_id”: „7515904334”, „servicer_name”: „SOME CORPORATION”}

Dodanie wartości do takiego węzła daje pożądany wynik: BigInteger.valueOf (Long.parseLong (wartość, 10))

Nie jestem pewien, czy to jest naprawdę na ten temat, ale ponieważ to pytanie było moim największym hitem, kiedy szukałem mojego rozwiązania, pomyślałem, że podzielę się tutaj z korzyścią dla innych, okłamuj mnie, którzy źle wyszukują. :RE


-1

W przypadku wartości całkowitych reprezentowanych przez a doublemożna użyć tego kodu, który jest znacznie szybszy niż inne rozwiązania.

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.