Why Rounding Double in Swift is a Pain (and How to Live with It in 2025)
\n\nEvery iOS developer sooner or later faces a situation: you need to show the user a product price of 99.99, but in the code it's 99.99000000000001. Sound familiar? Welcome to the world of rounding Double in Swift — a topic that has garnered thousands of views on Stack Overflow and continues to stir minds even in 2025.
The problem isn't Swift — the problem lies in the very nature of floating-point numbers (IEEE 754). A Double cannot accurately represent 0.1, just like 1/3 in the decimal system. But that's no excuse for the user. They need nice numbers on the screen.
\n\nIn this article, I'll show you 5 proven methods for rounding Double in Swift, break down their pros and cons, and give you a clear algorithm for choosing the right one for your task. Let's go!
\n\nMethod 1: Foundation — round() + pow(10, n) — The Classic
\n\nThe most obvious method that comes to mind: multiply the number by 10^n, round it, divide it back.
\n\nimport Foundation\n\nfunc roundDouble(_ value: Double, toPlaces places: Int) -> Double {\n let divisor = pow(10.0, Double(places))\n return round(value * divisor) / divisor\n}\n\nlet price = 99.995\nprint(roundDouble(price, toPlaces: 2)) // 100.0 (banker's rounding)\n\n\nPros:
\n- \n
- Simplicity and readability \n
- Works out of the box — no additional imports needed \n
Cons:
\n- \n
- Precision errors — due to Double, you might get 99.99000000000001 instead of 99.99 \n
- Banker's rounding issue — round() uses round half up, which is not always suitable for finance \n
- pow(10, n) — extra computation \n
This method is suitable for rough rounding in the UI, but not for financial calculations.
\n\nMethod 2: String(format:) — Rounding via String (Fastest for UI)
\n\nIf your end goal is to display the number on the screen, why work with Double at all? Convert it to a string right away.
\n\nlet value = 123.456789\nlet roundedString = String(format: "%.2f", value)\nprint(roundedString) // "123.46"\n\n// Back to Double (if needed)\nlet roundedDouble = Double(roundedString) ?? 0.0\n\n\nPros:
\n- \n
- Lightning fast — no extra mathematical operations \n
- Guaranteed correct number of decimal places in the output \n
- Localization support (decimal separator) \n
Cons:
\n- \n
- The result is a string; for further calculations, you need to convert it back (loss of precision) \n
- Not suitable for banker's rounding (round half up by default) \n
Ideal for displaying prices, percentages, ratings — anywhere where precision of ±0.01 is not critical.
\n\nMethod 3: NSDecimalNumber — The King of Financial Precision
\n\nWhen money is on the line, Double is evil. Use NSDecimalNumber — it stores numbers in decimal format without rounding errors.
import Foundation\n\nfunc roundDecimal(_ value: Double, toPlaces places: Int, roundingMode: NSDecimalNumber.RoundingMode = .plain) -> Double {\n let decimal = NSDecimalNumber(value: value)\n let handler = NSDecimalNumberHandler(\n roundingMode: roundingMode,\n scale: Int16(places),\n raiseOnExactness: false,\n raiseOnOverflow: false,\n raiseOnUnderflow: false,\n raiseOnDivideByZero: false\n )\n return decimal.rounding(accordingToBehavior: handler).doubleValue\n}\n\nlet amount = 99.995\nprint(roundDecimal(amount, toPlaces: 2, roundingMode: .bankers)) // 99.99 (banker's rounding!)\n\n\nPros:
\n- \n
- Full control over rounding — .plain, .down, .up, .b