Frage

Ich habe einen primitiven Schwimmer und ich brauche als primitive Doppel. zu verdoppeln, gibt mir seltsam zusätzliche Präzision einfach den Schwimmer Gießen. Zum Beispiel:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

Wenn jedoch anstelle von Gießen, I-Ausgang der Schwimmer als String und die Zeichenfolge als Doppel analysieren, ich bekommen, was ich will:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

Gibt es einen besseren Weg, als zu String zu gehen und zurück?

War es hilfreich?

Lösung

Es ist nicht, dass Sie wirklich zusätzliche Präzision bekommen - es ist, dass der Schwimmer nicht genau die Zahl darstellten Sie ursprünglich anstrebten. Die doppelte ist , die den ursprünglichen Schwimmer genau; toString wird die „extra“ Daten, die zeigen, die bereits vorhanden war.

Zum Beispiel (und diese Zahlen sind nicht richtig, ich mache die Dinge nur nach oben): Angenommen, Sie haben:

float f = 0.1F;
double d = f;

Dann könnte der Wert von f genau ,100000234523. d haben genau den gleichen Wert, aber wenn man es in einen String konvertieren es „Vertrauen“, dass es auf eine höhere Präzision genau ist, so wird nicht so früh abzurunden, und Sie werden die „zusätzlichen Ziffern“ sehen, die waren schon da, aber von Ihnen versteckt.

Wenn Sie in eine Zeichenfolge und zurück konvertieren, werden Sie mit einem doppelten Wert zu enden, die näher an dem String-Wert ist als der ursprüngliche Schwimmer war - aber das ist nur gut , wenn Sie glauben wirklich, dass der String-Wert ist das, was Sie wirklich wollen.

Sind Sie sicher, dass Float / Double der entsprechenden Arten sind hier zu verwenden, statt BigDecimal? Wenn Sie versuchen, Zahlen zu verwenden, die eine genaue Dezimalwerte haben (zum Beispiel Geld), dann BigDecimal ist eine angemessenere Art IMO.

Andere Tipps

Ich finde, in der binären Darstellung Umwandlung leichter, dieses Problem zu erreichen.

float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;

System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));

Sie können sehen, der Schwimmer auf die doppelte erweitert wird von 0s bis zum Ende, aber, dass die doppelte Darstellung von 0,27 ist ‚genauer‘, damit das Problem hinzuzufügen.

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

Dies ist aufgrund der Vertrag von Float.toString(float), die teilweise sagt:

  

Wie viele Ziffern müssen gedruckt werden   der Bruchteil [...]? Dort   muss mindestens eine Ziffer sein,   stellt den Bruchteil, und   darüber hinaus, dass so viele, aber nur so viele,    mehr Stellen als nötig sind, um eindeutig zu   unterscheidet das Argument Wert von   benachbarte Werte vom Typ float. Das   wird angenommen, dass x die genaue ist   mathematischer Wert, der durch die dargestellte   Dezimaldarstellung hergestellt von   diese Methode für ein endliches ungleich Null   Argument f. Dann muss f sein der Schwimmer   Wert am nächsten x; oder, wenn zwei Schwimmer   Werte sind ebenso nahe an x, dann f   muss einer von ihnen sein und die am wenigsten   Bit der Mantisse von   f muss 0 sein.

Ich habe dieses Problem heute begegnet und nicht refactor zu BigDecimal verwenden konnte, weil das Projekt wirklich riesig. Allerdings fand ich Lösung mit

Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

Und das funktioniert.

Beachten Sie, dass Aufruf result.doubleValue () gibt 5623,22998046875

Aber Aufruf doubleResult.doubleValue () gibt korrekt 5.623,23

Aber ich bin nicht ganz sicher, ob sein eine richtige Lösung.

Verwenden Sie einen BigDecimal statt float / double. Es gibt eine Menge von Zahlen, die (beispielsweise 0.1) nicht als binäre Gleitkomma dargestellt werden. So müssen Sie entweder immer um das Ergebnis zu einer bekannten Präzision oder BigDecimal verwenden.

Siehe http://en.wikipedia.org/wiki/Floating_point für weitere Informationen .

Ich fand die folgende Lösung:

public static Double getFloatAsDouble(Float fValue) {
    return Double.valueOf(fValue.toString());
}

Wenn Sie float und double statt Float und Double verwenden Sie die folgenden Schritte aus:

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}

Floats, von der Natur, sind ungenau und haben immer ordentlich Rundung „Probleme“. Wenn Präzision wichtig ist, dann könnten Sie Ihre Anwendung Refactoring Dezimal oder BigDecimal zu verwenden.

Ja, den Schwimmer ist rechnerisch schneller als Dezimalzahlen, weil die auf dem Prozessor-Unterstützung. Allerdings müssen Sie schnell oder genau wollen?

Weitere Informationen dazu kommt unter Punkt 48 - Vermeiden float und double, wenn genaue Werte erforderlich sind, von Effective Java 2. Auflage von Joshua Bloch. Dieses Buch ist Marmelade mit guten Sachen gepackt und auf jeden Fall einen Blick wert.

funktionierts?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top