2013-01-14 7 views
11

I einen Gleitkommawert haben: 12345,6489Falsche Rundung des Schwimmers, wenn ToString Verwendung ("F1")

Wenn I formatiert diese Verwendung:

(12345.6489f) .ToString ("F1")

Dann bekomme ich ein Ergebnis von

12345,7

Aber das ist falsch, da es 12.345,6 sein sollte.

Versteht jemand, warum dies auftreten könnte? Ein weiterer Hinweis ist, dass Casting zu verdoppeln, bevor ich formatiere das richtige Ergebnis zurückgibt, und wenn mein Float-Wert ein wenig kleiner ist, zum Beispiel 1234.6489, dann bekomme ich auch das richtige Ergebnis.

+1

@DavidStratton: 'Double' ist auch nicht genau, und wird ähnliche Kuriositäten geben. Sie haben nur unterschiedliche Genauigkeiten und unterschiedliche Bereiche. –

+0

@JonSkeet - danke für die Klarstellung! Ich habe den Kommentar gelöscht. – David

+0

Single.ToString macht etwas sehr merkwürdiges. Ich denke, du musst auf die IL schauen. Die Dokumentation (http://msdn.microsoft.com/en-us/library/f71z6k0c.aspx) sagt "Standardmäßig enthält der Rückgabewert nur 7 Stellen der Genauigkeit, obwohl ein Maximum von 9 Ziffern intern beibehalten wird" aber ich ' Ich habe keine Ahnung, was das bedeutet. –

Antwort

2

Dies scheint auf eine Frage bezogen werden ich vor einiger Zeit gefragt: Round-twice error in .NET's Double.ToString method

Beachten Sie, dass, wenn Sie .ToString("G") auf Ihre Nummer anrufen, wird es richtig 12345.65 gerundet. Wenn Sie die gerundete Zahl auf eine Dezimalstelle runden, tritt das Problem auf.

Als ich meine eigene Frage früher untersuchte, fand ich auch einige Beispiele, die nicht als rund-zweimal Fehler erklärt werden konnten, also überprüfen Sie diesen Thread auch.

Zusatz: Beachten Sie, dass jede Zahl, die (genau) dargestellt werden kann durch eine float kann auch (mit einer Menge von Null-Bits) dargestellt werden durch eine double. Man kann den folgenden Trick verwenden (was die Frage auch erwähnt):

float x = 12345.6489f; 
string trick = ((double)x).ToString("F1"); 
1

Danke für diese Frage! Es ist sehr interessant, Gegenstand von Untersuchungen zu sein. Aber ich wollte andere Partei einer Medaille erwähnen. Sie fragte die folgende:

(12345.6489f) .ToString ("F1")

Dann bekomme ich ein Ergebnis von

12345,7

Aber das ist falsch, weil es sein sollte 12345.6.

Nun, ich frage mich, wie Sie herausgefunden haben, was richtig ist und was falsche Ausgabe dieser Zeichenfolge Routine Formatierung? Diese Formatierungszeichenfolgen sollten nicht für Rundungszwecke verwendet werden. Und Dokumentation deutlich says darüber:

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#FFormatString


Ehrlich gesagt, als ich sah erst an der Nummer aus Ihrer Frage - die erste Idee war etwa Algorithmus Runden, die Hans Passant in seiner Antwort erwähnt. Ich bin also nicht einmal überrascht, dass ein solcher Algorithmus gewählt wurde, er ist eigentlich ziemlich intuitiv :) Ich wäre sogar nicht überrascht, wenn man ihn als Algorithmus für die Formatierung von Fließkommazahlen betrachten würde.Es wäre immer noch ziemlich genau und gültig.

Also, trotz der Tatsache, dass alle dies ist sehr interessant und sah aus wie ein Fehler/Paradox/Wunder, das ist in der Tat nur unsere falschen Erwartungen von der Funktion, die entwickelt wurde (und tatsächlich ziemlich gut) etwas anderes.

+0

. Ich dachte, ich hätte irgendwo gelesen, dass das Stringformat die Zahl für Sie runden soll, weshalb ich dachte, dass 12345.6 wäre die richtige Antwort. Ja Math.Round wäre auf jeden Fall zuverlässiger! –

+0

Math.Round hilft überhaupt nicht. Das gibt einen Gleitkommawert zurück. Sie müssen immer noch eine Zeichenfolge abrufen, die Sie zu ToString zurückführt. Sie müssen als Teil der Umwandlung in eine Zeichenfolge runden. Dies ist kritisch, da der Fließkommawert eine binäre Repräsentation verwendet, die String-Repräsentation jedoch dezimal ist. –