Warum Double-Rundung in Swift eine Qual ist (und wie man 2025 damit lebt)
Jeder iOS-Entwickler stößt früher oder später auf diese Situation: Dem Benutzer soll ein Preis von 99.99 angezeigt werden, aber im Code steht 99.99000000000001. Kommt Ihnen das bekannt vor? Willkommen in der Welt der Double-Rundung in Swift – einem Thema, das auf Stack Overflow tausende Aufrufe gesammelt hat und selbst im Jahr 2025 die Gemüter erhitzt.
Das Problem liegt nicht an Swift – das Problem liegt in der Natur von Gleitkommazahlen (IEEE 754). Ein Double kann 0.1 nicht exakt darstellen, genauso wenig wie 1/3 im Dezimalsystem. Aber für den Benutzer ist das keine Entschuldigung. Er möchte schöne Zahlen auf dem Bildschirm sehen.
In diesem Artikel zeige ich Ihnen 5 bewährte Methoden zur Double-Rundung in Swift, analysiere ihre Vor- und Nachteile und gebe Ihnen einen klaren Algorithmus zur Auswahl für Ihre Aufgabe. Los geht's!
Methode 1: Foundation – round() + pow(10, n) – der Klassiker
Der naheliegendste Weg: Multiplizieren Sie die Zahl mit 10^n, runden Sie, teilen Sie wieder zurück.
import Foundation
func roundDouble(_ value: Double, toPlaces places: Int) -> Double { let divisor = pow(10.0, Double(places)) return round(value * divisor) / divisor}
let price = 99.995print(roundDouble(price, toPlaces: 2)) // 100.0 (kaufmännisches Runden)Vorteile:
- Einfachheit und Lesbarkeit
- Funktioniert sofort – keine zusätzlichen Imports nötig
Nachteile:
- Genauigkeitsfehler – aufgrund von Double kann 99.99000000000001 statt 99.99 herauskommen
- Problem mit kaufmännischem Runden – round() verwendet round half up, was nicht immer für Finanzen geeignet ist
- pow(10, n) – zusätzliche Berechnungen
Diese Methode eignet sich für grobe Rundungen in der UI, aber nicht für Finanzberechnungen.
Methode 2: String(format:) – Runden über einen String (am schnellsten für die UI)
Wenn Ihr Endziel darin besteht, eine Zahl auf dem Bildschirm anzuzeigen, warum überhaupt mit Double arbeiten? Wandeln Sie sie direkt in einen String um.
let value = 123.456789let roundedString = String(format: "%.2f", value)print(roundedString) // "123.46"
// Zurück in Double (falls nötig)let roundedDouble = Double(roundedString) ?? 0.0Vorteile:
- Blitzschnell – keine überflüssigen mathematischen Operationen
- Garantiert korrekte Anzahl von Nachkommastellen im Ergebnis
- Unterstützt Lokalisierung (Dezimaltrennzeichen)
Nachteile:
- Ergebnis ist ein String, für weitere Berechnungen muss zurück konvertiert werden (Genauigkeitsverlust)
- Nicht geeignet für kaufmännisches Runden (standardmäßig round half up)
Ideal für die Anzeige von Preisen, Prozenten, Bewertungen – überall dort, wo eine Genauigkeit von ±0.01 nicht kritisch ist.
Methode 3: NSDecimalNumber – der König der Finanzgenauigkeit
Wenn es um Geld geht, ist Double böse. Verwenden Sie NSDecimalNumber – es speichert Zahlen im Dezimalformat ohne Rundungsfehler.
import Foundation
func roundDecimal(_ value: Double, toPlaces places: Int, roundingMode: NSDecimalNumber.RoundingMode = .plain) -> Double { let decimal = NSDecimalNumber(value: value) let handler = NSDecimalNumberHandler( roundingMode: roundingMode, scale: Int16(places), raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false ) return decimal.rounding(accordingToBehavior: handler).doubleValue}
let amount = 99.995print(roundDecimal(amount, toPlaces: 2, roundingMode: .bankers)) // 99.99 (kaufmännisches Runden!)Vorteile:
- Volle Kontrolle über die Rundung – .plain, .down, .up, .b