Dienstag, 27. Juli 2010

Richtig runden mit C#

In diesem Post stelle ich 3 grundlegende Funktionen zum Runden von Zahlen mit C# vor.
Wie auch andere mathematische Funktionen sind diese (logischerweise) in der Klasse Math untergebracht.
Zum "standardmäßigen" Runden gibt es die Funktion Round(). Diese erwartet als 1. Parameter die zu rundende Zahl und als 2. optional die Anzahl der Dezimalstellen nach dem Runden. Wird diese Anzahl nicht übergeben, nimmt die Funktion 0 als Standardwert an, d.h. die Zahl wird auf die nächstgelegene ganze Zahl gerundet. Liegt die Zahl genau zwischen 2 Zahlen, wird die gerade Zahl genommen.
Es gibt aber noch 2 weitere interessante Funktionen: Ceiling() und Floor().
Beide Funktionen runden auf ganze Zahlen, erstere auf die nächsthöhere und zweite auf die nächsttiefere.
Das folgende Beispiel sollte diese einfachen Zusammenhänge verdeutlichen:

            decimal d = (decimal)1.5642; // hier muss "1.5642" manuell über (decimal) in einen Decimal - Wert konvertiert werden, da C# Kommazahlen standardmäßig als double - Wert interpretiert

            decimal RoundedIntegerNumber = Math.Round(d); // auf ganze Zahl runden = 2
            decimal RoundedDecimalNumber = Math.Round(d, 2); // auf 2 Nachkommastellen runden = 1.56

            decimal NextHigherNumber = Math.Ceiling(d); // auf nächsthöhere Zahl runden = 2
            decimal NextLowerNumber = Math.Floor(d); // auf nächsttiefere Zahl runden = 1

Kommentare:

  1. Die Konvertierung von 1.5642 (was ein Double ist) in Decimal ist unnötig, da man durch das PostFix "m" ein Literal direkt als Decimal angeben kann.

    Richtig wäre also:
    decimal d = 1.5642m;

    AntwortenLöschen
  2. Für Form anwendungen wie geht das da?

    AntwortenLöschen
  3. Da geht es natürlich genau gleich.

    AntwortenLöschen
  4. Richtig, wie Andreas bereits gesagt hat, ist der Code exakt der selbe. Der Code von Konsolen und Windows Forms Apps unterscheidet sich nicht - bei Windows Forms Apps stehen meistens nur mehr Bibliotheken und damit Funktionen zur Nutzung bereit.

    AntwortenLöschen
  5. Und wenn man eine double-Zahl mit einer bestimmten Zahl an Nachkommastellen anzeigen lassen möchte, gilt folgende Syntax:


    Console.WriteLine("gerundet: {0:f2}",zahl);


    Dabei ist der Teil innerhalb der geschweiften Klammern näher zu betrachten:

    Die Ausgabe von Variablen setze ich als bekannt voraus.
    Erweitert man diesen Teil {0} um :f2 , so wird die Zahl in der Ausgabe auf zwei Nachkommastellen gerundet. (Genauso ist es natürlich mit beliebig vielen Stellen, dafür muss man eben nur die Ziffer hinter dem "f" entsprechend ändern.

    AntwortenLöschen
  6. Warum wird bei Zahlen mit .5 den immer unterschiedlich gerundet? So wird wenn ich zum Beispiel 1.5 runden möchte 2 ausgegeben. Bei 2.5 aber auch 2 dann bei 3.5 wieder 4 und bei 4.5 auch 4. Also scheinbar immer abwechselnd je ob gerade oder ungerade Zahl vor dem Komma wird auf oder abgerundet. Wenn ich aus der .5 ein .51 mache passt es.

    AntwortenLöschen
    Antworten
    1. nicht ganz, denn wenn du immer 0.01 dazuzählst, dann bekommst du beispielsweise bei der Ursprungszahl 3.49 +0.01 = 3.5, was auf die nächste gerade Zahl gerundet werden würde -> 4.
      3.49 würde also auf 4 gerundet werden, was mathematisch falsch ist!

      Löschen
  7. Hi,
    vielen Dank für den Hinweis, das war mir bis eben selber noch nicht bewusst.
    Die Lösung steht aber auf der MSDN Seite:

    Return Value
    The whole number nearest parameter d. If d is halfway between two whole numbers, one of which by definition is even and the other odd, then the even number is returned.

    Liegt die zu rundenen Zahl also genau in der Mitte zweier Zahlen, wird die gerade Zahl zurückgegeben.
    Den Post habe ich entsprechend angepasst.

    AntwortenLöschen
  8. ich habe mal ne frage wie rundet man wen nach der größeren zahl eine kleine steht also bsp.3.54 ?

    AntwortenLöschen
  9. Hallo,
    Das kommt darauf an, auf welche stelle gerundet werden soll.

    Beispiele:
    Auf eine Ganzzahl:
    3.54 -> 4
    Aufgrund der 5 nach dem Komma.

    Auf die 1. Nachstelle:
    3.54 -> 3.5
    Aufgrund der 4 nach der 1. Nachkommastelle (5).

    3.56 -> 3.6
    Aufgrund der 6 Nach der 1. Nachkommastelle (5).


    Generell wird ab ab 5 aufgerundet, ansonsten abgerundet.

    Grüße
    Postremus

    AntwortenLöschen
  10. Ich verstehe nichts!! wenn meine zahl jetzt z.b
    3.79 wäre und ich auf 2 stellen nach dem komma runden muss wie würde mein ergebniss lauten ?!?!

    AntwortenLöschen
    Antworten
    1. Auf 2 Stellen nach dem Komma? Dann gibt es ja nichts zu runden und das Ergebnis würde 3.79 lauten.
      Generell ist es so wie Postremus es oben schön erklärt hat, es wird also das Standard "Schulrunden" verwendet.
      Etwas "anders" verhält sich C# eben nur, wenn die zu rundende Zahl genau in der Mitte zweier Zahlen liegt.

      Löschen
  11. Daumen hoch! Hat mir geholfen. :-)

    AntwortenLöschen
  12. Wie kann man immer abruden, wenn die zu rundende Zahl genau in der Mitte zweier Zahlen liegt
    z.B 1,5 runden zu 1.0, 2.5 zu 2.0 und 3.5 zu 3.0

    AntwortenLöschen
    Antworten
    1. 1,5 wären 2,00
      2,5 wären 3,00


      aber so etwas ist Schulstoff der 4 Klasse? o.O

      Löschen
    2. Math.Floor(1,5) ergibt 1

      Löschen
    3. Das geht folgendermaßen:

      Math.Round(1.5, MidpointRounding.ToEven);


      Gruß

      Löschen
    4. Math.Round(1.5, MidpointRounding.ToEven); // Ausgabe 1
      Math.Round(2.5, MidpointRounding.ToEven); // Ausgabe 2
      Math.Round(3.5, MidpointRounding.ToEven); // Ausgabe 3
      ...

      Löschen
  13. "kaufmännisches Runden" nennt sich das - und 1.5 liegt nicht genau in der Mitte, sondern ist genau betrachtet im oberen Teil. 1.00-1.49 zu 1 und 1.50-1.99 zu 2.

    AntwortenLöschen
  14. double test = 5 / 2;
    textbox.Text = Math.Round(test, 2);

    angezeigt wird mir "2", was mache ich falsch?

    Grüße

    AntwortenLöschen
    Antworten
    1. Hallo,
      das liegt hier nicht an der Round Funktion, sondern an der Eingabe der Zahlen.
      Die Zahlen 5 und 2 werden bei Eingabe ohne Nachkommastellen als ganze Zahlen interpretiert (Integer). Der Compiler findet also eine Division von 2 Integerzahlen und führt entsprechend eine ganzzahlige Division durch, mit Ergebnis 2. Da links der Typ double steht, wird das Ergebnis dann in einen double umgewandelt, hierbei kommt aber 2.0 raus. Beim Runden wird dann richtig auf glatt 2 gerundet.
      Um die Division richtig durchzuführen, musst du eine Zahl manuell in einen double umwandeln, z.B. so:
      double test = (double)5 / 2;

      Grüße
      Oliver

      Löschen