CodeGym /Kurse /C# SELF /Runden von Fließkommazahlen

Runden von Fließkommazahlen

C# SELF
Level 6 , Lektion 4
Verfügbar

1. Einführung

Im echten Leben kommt es selten vor, dass Geld bis auf hundert Billionstel Euro ausgezahlt wird oder die Länge eines Zimmers auf hundertstel Millimeter gemessen wird. In der Programmierung ist es genauso: Die Ergebnisse mit double oder float sind oft “zu viele Nachkommastellen”.

Hier ist ein klassisches Problem:

double result = 10.0 / 3.0;
Console.WriteLine(result); // 3.3333333333333335
Division mit Gleitkommazahlen — Ergebnis mit "Schwanz"

Aber was, wenn wir diese Zahl zum Beispiel nur mit zwei Nachkommastellen ausgeben wollen (damit der User nicht “erschreckt” wird)? Dafür brauchen wir das Runden.

2. Die wichtigsten Rundungsmethoden in C#

C# bietet mehrere Möglichkeiten, eine Fließkommazahl zu runden. Und jetzt wird’s spannend: Runden ist nicht gleich Runden! Lass uns die wichtigsten Varianten anschauen und verstehen, worin sie sich unterscheiden.

1) Die Funktion Math.Round — klassisches Runden

Die beliebteste Methode ist Math.Round. Sie rundet eine Zahl auf die nächste ganze Zahl (oder auf die gewünschte Anzahl Nachkommastellen).


Math.Round(zahl[, anzahl_stellen[, MidpointRounding]])
Syntax von Math.Round
  • zahl — was wir runden.
  • anzahl_stellen — wie viele Nachkommastellen bleiben sollen (Standard ist 0, also auf ganze Zahl).
  • MidpointRounding — Methode zum Runden von "Halbwerten" (dazu gleich mehr).

Beispiele:

double x = 2.71828;

Console.WriteLine(Math.Round(x));         // 3
Console.WriteLine(Math.Round(x, 2));      // 2.72
Console.WriteLine(Math.Round(x, 3));      // 2.718

Visualisierung:

Eingabewert Math.Round(x) Math.Round(x, 2)
2.3 2 2.3
2.5 2 2.5
2.7 3 2.7
2.71828 3 2.72

Rückgabetyp:
Alle Funktionen in dieser Vorlesung geben double zurück, also kann es zu einem Fehler kommen, wenn du das Ergebnis zuweisen willst:

double result = 10.0 / 5.0;     // Ergebnis 2.0
int x = Math.Round(x);          // Fehler! Du kannst nicht einfach double in int speichern

Wenn du einen double in eine int-Variable speichern willst, musst du das explizit casten:

double result = 10.0 / 5.0;     // Ergebnis 2.0
int x = (int) Math.Round(x);    // Funktioniert super!

2) Runden nach oben oder unten

C# unterstützt nicht nur das “klassische” Runden, sondern auch das erzwungene Runden nach oben oder unten.

Abrunden (Math.Floor)

Die Methode Math.Floor “schneidet” einfach den Nachkommabereich ab (in Richtung minus Unendlichkeit). Also immer nach unten!

Console.WriteLine(Math.Floor(2.99));   // 2
Console.WriteLine(Math.Floor(-2.99));  // -3

Aufrunden (Math.Ceiling)

Die Methode Math.Ceiling ist das Gegenteil von Floor: Sie rundet immer nach oben (in Richtung plus Unendlichkeit).

Console.WriteLine(Math.Ceiling(2.01));   // 3
Console.WriteLine(Math.Ceiling(-2.01));  // -2

Vergleichstabelle:

Funktion 2.3 -2.3
Math.Round 2 -2
Math.Floor 2 -3
Math.Ceiling 3 -2

3) Truncate: einfach Nachkommastellen abschneiden

Die Methode Math.Truncate ist wie ein “ruhiger Chirurg”. Sie entfernt einfach den Nachkommabereich, ohne sich um mathematische Korrektheit beim Runden zu kümmern. Wenn x positiv ist — wie Floor, wenn negativ — wie Ceiling.

Console.WriteLine(Math.Truncate(2.99));   // 2
Console.WriteLine(Math.Truncate(-2.99));  // -2

3. Wie funktioniert Math.Round bei “Halbwerten”? (MidpointRounding)

Stell dir vor: Du hast 2.5. Wohin runden? Es liegt genau zwischen 2 und 3. In der Mathematik gibt es zwei beliebte Ansätze:

  • Runden nach oben (“zum nächsthöheren”)
  • Runden zur nächsten geraden Zahl (Banker's rounding)

C# verwendet standardmäßig den zweiten Ansatz — Runden zur nächsten geraden Zahl (“banker's rounding”, oder “Runden zur geraden Zahl”).

Console.WriteLine(Math.Round(2.5)); // 2
Console.WriteLine(Math.Round(3.5)); // 4

Warum? Weil von zwei gleich weit entfernten Ganzzahlen die gerade “gewinnt”. Das ist so gemacht, damit bei vielen Rundungen kein systematischer Fehler nach oben oder unten entsteht. Das ist z.B. bei großen Geldsummen in Banken sehr wichtig (daher der Name).

Wenn du immer nach oben runden willst, kannst du den gewünschten Modus explizit angeben:

// Immer "von Null weg" runden
Console.WriteLine(Math.Round(2.5, 0, MidpointRounding.AwayFromZero)); // 3
Console.WriteLine(Math.Round(-2.5, 0, MidpointRounding.AwayFromZero)); // -3

Tabelle der MidpointRounding-Modi:

Eingabewert Round (Standard) AwayFromZero ToZero / ToEven
2.5 2 3 2
3.5 4 4 4
-2.5 -2 -3 -2

4. Runden auf gewünschte Nachkommastellen: vergiss nicht die "Achten" und "Dreien"!

Manchmal muss man nicht auf ganze Zahlen runden, sondern z.B. auf zwei Nachkommastellen (zum Beispiel für Geldbeträge oder Prozente).

double price = 149.9999;
double roundedPrice = Math.Round(price, 2);
Console.WriteLine(roundedPrice); // 150

Was, wenn wir einfach “überflüssige” Nachkommastellen abschneiden wollen, aber nicht runden? Zum Beispiel aus 123.4567 eine 123.45 machen.

Das geht mit einem kleinen Trick:

double num = 123.4567;
double result = Math.Floor(num * 100) / 100;
Console.WriteLine(result); // 123.45

Wir “verschieben” das Komma manuell, schneiden die Nachkommastellen ab und verschieben zurück.

5. Ausgabeformatierung vs echtes Runden

WICHTIG!

Ausgabeformatierung ({x:F2}) ist nicht immer "echtes" Runden, sondern nur eine “Maske”, wie die Zahl auf dem Bildschirm aussieht. Im Speicher bleibt sie ein langes “schwänziges” double. Wenn du wirklich runden und speichern willst, benutze Math.Round.

Hier ein Beispiel, wo der Unterschied kritisch sein kann:

double value = 2.555;
Console.WriteLine($"{value:F2}"); // 2.56
Console.WriteLine(Math.Round(value, 2)); // 2.56

double stored = Math.Round(value, 2);
Console.WriteLine(stored); // 2.56

// Aber wenn du einfach nur mit Format ausgibst, ohne zu runden...
Console.WriteLine($"{value:F2}"); // 2.56, aber im Speicher — 2.555

6. Typische Fehler und Besonderheiten

  • Benutze kein Runden für exakte Finanzberechnungen mit double! Für Geld gibt es in .NET den speziellen Typ decimal — der “spielt nicht” mit Gleitkomma (mehr dazu in einer der nächsten Vorlesungen).
  • Traurige “hängende Achten”: Wegen binärer Speicherung werden nicht alle Zahlen “logisch” gerundet. Zum Beispiel kann 0.1 + 0.2 ganz und gar nicht 0.3 sein.
  • Verwechsele Math.Floor und Math.Round nicht! Der erste immer nach unten, der zweite — wie die Mathematik es will.
  • Unkontrollierte Fehlerakkumulation: Wenn du oft während der Berechnung rundest (z.B. in einer Schleife), kann das Endergebnis plötzlich “weglaufen”. Meistens ist es besser, nur das Endergebnis zu runden, nicht alle Zwischenschritte.

7. Abschlusstabelle: Welche Methode macht was?

Eingabewert Math.Round(x) Math.Floor(x) Math.Ceiling(x) Math.Truncate(x)
3.2 3 3 4 3
3.5 4 3 4 3
-3.2 -3 -4 -3 -3
-3.5 -4 -4 -3 -3

8. Fun Facts

  • Einmal hat die NASA eine Raumsonde verloren, weil sie Koordinaten nicht streng genug gerundet und metrische/imperiale Einheiten verwechselt haben. Moral: Runde bewusst!
  • Banken sind schon lange auf “banker's rounding” umgestiegen, um keine Cents zu verlieren — früher wurde immer nach oben gerundet und die Kunden haben bei jeder Überweisung Bruchteile eines Cents verloren.
  • In C# gibt es sogar die Methode Math.Sign, die das Vorzeichen einer Zahl zurückgibt — manchmal praktisch vor dem Runden, um selbst zu entscheiden, wohin “abgeschnitten” wird.
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION