2012-08-24 5 views
18

Warum ist es, dass, wenn ich folgendes tun ...Brauchen Sie Hilfe auf 2 Dezimalstellen gerundet

Math.Round(0.75, 1, MidpointRounding.AwayFromZero) 

I 0,8

bekommen, aber wenn ich folgendes tun ...

Math.Round(0.575, 2, MidpointRounding.AwayFromZero) 

Ich bekomme nicht 0.58. Stattdessen bekomme ich 0,57. Ich möchte alles, was 5 und höher ist, also 0,575 sollte 0,58 sein.

+0

Die [erste Antwort in dieser Frage] (http://stackoverflow.com/q/5641616/62576) sollte helfen, diese zu beantworten. –

+0

@KenWhite: Ich bin mir nicht sicher, ob es wird. Das Problem ist, dass bei richtiger Mathematik das Runden von '.575' auf zwei Dezimalstellen weg von Null' .58' ergibt, aber dies ist nicht das beobachtete Ergebnis. In diesem Fall handelt es sich um Floating Poitn-Darstellungen. – Chris

+0

@Chris: Du hast Recht. :-) Ich benutze hauptsächlich Delphi, und Round() behandelt Dinge wie diese in den meisten Fällen gut. Ich habe gerade C# eingecheckt und kann das Problem sehen. –

Antwort

30

Das Problem wird sein, dass Sie 0.575 nicht genau als binäre Fließkommazahl (zB ein Doppel) darstellen können. Obwohl ich nicht genau weiß, scheint es, dass die Darstellung am nächsten ist wahrscheinlich nur ein bisschen niedriger und so beim Runden verwendet es die wahre Darstellung und rundet ab.

Wenn Sie dieses Problem vermeiden möchten, verwenden Sie einen geeigneteren Datentyp. decimal wird tun, was Sie wollen:

Math.Round(0.575M, 2, MidpointRounding.AwayFromZero) 

Ergebnis: 0.58

Der Grund, dass 0,75 tut das Richtige ist, dass es einfach in binären Gleitkomma darstellen, da es einfach ist, 1/2 + 1/4 (dh 2^-1 + 2^-2). Im Allgemeinen kann jede endliche Summe von Zweierpotenzen im binären Fließkomma dargestellt werden. Ausnahmen sind, wenn Ihre Potenzen von 2 einen zu großen Bereich überspannen (zB 2^100 + 2 ist nicht genau darstellbar).

bearbeiten hinzuzufügen:

Formatting doubles for output in C# in Bezug auf Interesse sein könnte, warum die so schwer zu verstehen, zu verstehen, dass 0.575 nicht wirklich 0.575 ist. Der DoubleConverter in der angenommenen Antwort zeigt, dass 0,575 als eine exakte Zeichenkette 0.5749999999999999555910790149937383830547332763671875 ist. Sie können daraus sehen, warum das Runden 0,57 ergibt.

+2

Danke für alle Infos Jungs. Ich habe mein Double auf eine Dezimalzahl umgestellt und das macht den Trick. Vielen Dank! –

2

Es wird durch einen Mangel an Präzision mit Doppel/Dezimalstellen verursacht (d. H. - die Funktion immer gibt das Ergebnis, das Sie erwarten).

Siehe die folgende Verbindung: MSDN on Math.Round

Hier ist das relevante Zitat:

Wegen des Verlustes der Präzision, die von der Darstellung der dezimalen Werte als Gleitkommazahlen oder das Durchführen arithmetische Operationen auf schwimmenden führen -Point-Werte, in einigen Fällen scheint die Round-Methode (Double, Int32, MidpointRounding) die vom mode-Parameter angegebenen Mittelpunktwerte nicht zu runden. Dies wird im folgenden Beispiel veranschaulicht, in dem 2.135 statt 2.14 auf 2.13 gerundet wird tritt auf, weil intern die Methode den Wert mit 10 Ziffern multipliziert und die Multiplikation op In diesem Fall leidet die Genauigkeit an Genauigkeit.

7

System.Math.Round Die Methode verwendet die Double Struktur, die, wie die anderen darauf hingewiesen haben, zu Gleitkommagenauigkeit fehleranfällig ist. Die einfache Lösung ich für dieses Problem gefunden, wenn ich traf sie die System.Decimal.Round Methode zu verwenden war, die aus dem gleichen Problem leidet nicht und erfordert nicht Ihre Variablen als Dezimalzahlen redifining:

Decimal.Round(0.575, 2, MidpointRounding.AwayFromZero) 

Ergebnis: 0.58