2016-06-24 20 views
5

Wie an vielen Stellen (wie Why can't decimal numbers be represented exactly in binary?) erläutert ist, werden nicht alle Dezimalzahlen können als Fließkommawerte (wie beispielsweise in einem float in Java gespeichert) dargestellt werden.Wie kann Java Round-trip String -> float -> String sogar für (einige) Werte nicht als float darstellbar?

Das typische Beispiel gegeben ist „0,2“. Nach diesen geschickten IEEE 754 Converter ist die am nächsten zu 0,2 float etwa ,20000000298023224, so Parsen „0,2“ als ein float dieses Ergebnis liefern sollte.

Allerdings habe ich festgestellt, dass Java in der Lage sein scheint das Unmögliche zu tun:

String number="0.2"; 
float f = Float.parseFloat(number); 
System.out.println("Result of roundtrip String -> float -> String: "+f); 

druckt:

Ergebnis des Umlaufs String -> float -> String: 0,2

Test on IDeone.com

Woher weiß Java, dass ich wollte die (gerundete) Ausgabe "0.2", anstelle der genauen Ausgabe "0.20000000298023224" wie oben erklärt?

Der Javadocs of Float.toString() Versuch, dies zu erklären:

Wie viele Stellen müssen für den Bruchteil m oder gedruckt werden? Es muss mindestens eine Ziffer geben, um den Bruchteil darzustellen, und darüber hinaus so viele, aber nur so viele, mehr Ziffern wie benötigt werden eindeutig den Argumentwert von benachbarten Werten des Typs float unterscheiden.

Leider verwirrt mich das noch mehr. Warum ermöglicht es "Drucken von so vielen Ziffern, wie erforderlich, um den Argumentwert eindeutig zu unterscheiden", dass Java "0,2" ausgibt?

Idealerweise würde die Antwort auch erklären warum dieser Druckalgorithmus gewählt wurde. Es geht darum, (einige) Rundreisen zu machen, wie in diesem Beispiel? Gibt es eine andere Motivation?

+1

Wo ist Jon Skeet, wenn Sie ihn brauchen? Hat er BREXIT? – GhostCat

+0

Sie wissen, dass selbst die Eingabe von 0,21 oder 0,2000001 oder etwas Ähnliches auch 0,2 ergibt? Siehe http://stackoverflow.com/questions/17464675/convert-string-to-decimal-number-with-2-decimal-places-in-java – mylenereiners

+0

Es gibt 7 Nullen, 10^7 = 2^23 also wahrscheinlich die 3 Byte Mantisse eines 4 Byte Float wird erreicht. Also hier könnte es immer noch regelmäßig sein. Es ist öfter C und C++, die ein wenig schummeln, um bessere Ergebnisse zu erzielen (mein Eindruck). –

Antwort

1

Ich denke, 0.2 gehört zu den "Value Set Conversion".

+0

Hm, ich denke, das ist ein anderes (wenn auch verwandtes) Gebiet. Wertsatzkonvertierungen scheinen auf Zwischenergebnisse in FP-Berechnungen und nicht auf Konvertierungen anzuwenden. – sleske

+0

Siehe §5.2 der gleichen Seite. – mauretto

2

Die Abrundung des Ausgangs ist nicht wegen irgendeine Druckalgorithmus. Es ist wegen der Größe von float. Wenn Sie das tun:

String fs = "0.2"; 
double f = Float.parseFloat(fs); 
System.out.println(f); 

Sie erhalten:

0,20000000298023224

Test on Ideone.com

deutlich Dies zeigt, dass der String "0.2" als 0,20000000298023224 analysiert wird, aber die Schwimmer Daten -Typ ist nicht in der Lage, es zu halten und rundet es auf 0,2 auf. double Datentyp ist in der Lage, diese Daten zu halten, und daher, wenn Sie analysieren es als float, aber speichern Sie es in einem Doppel, erhalten Sie die erwartete Ausgabe.

+0

Wenn ich es als doppelt analysierte, ergab es immer noch 0,2 – 4castle

+0

Nein. Auf meiner IDE ist es das. Warte, ich werde es online versuchen, um es dir zu zeigen. – Hackerdarshi

+0

@ 4castle Sehen Sie dies: http://ideone.com/sjWAZS – Hackerdarshi