Por que arredondar Double em Swift é uma dor (e como lidar com isso em 2025)
Todo desenvolvedor iOS, mais cedo ou mais tarde, se depara com a situação: precisa mostrar ao usuário o preço de um produto 99.99, mas no código aparece 99.99000000000001. Familiar? Bem-vindo ao mundo do arredondamento de Double em Swift — um tópico que acumulou milhares de visualizações no Stack Overflow e continua agitando as mentes mesmo em 2025.
O problema não está no Swift — o problema está na própria natureza dos números de ponto flutuante (IEEE 754). Double não consegue representar exatamente 0.1, assim como 1/3 no sistema decimal. Mas para o usuário, isso não é desculpa. Ele precisa de números bonitos na tela.
Neste artigo, mostrarei 5 maneiras comprovadas de arredondar Double em Swift, analisarei seus prós e contras e darei um algoritmo claro para escolher a melhor para sua tarefa. Vamos lá!
Método 1: Foundation — round() + pow(10, n) — o clássico do gênero
A maneira mais óbvia que vem à mente: multiplicar o número por 10^n, arredondar e dividir de volta.
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 (arredondamento bancário)Prós:
- Simplicidade e legibilidade
- Funciona "de fábrica" — sem necessidade de imports adicionais
Contras:
- Erros de precisão — devido ao Double, pode resultar em 99.99000000000001 em vez de 99.99
- Problema com arredondamento bancário — round() usa round half up, o que nem sempre é adequado para finanças
- pow(10, n) — cálculos extras
Este método é adequado para arredondamento aproximado na interface do usuário, mas não para cálculos financeiros.
Método 2: String(format:) — arredondamento via string (o mais rápido para UI)
Se seu objetivo final é mostrar o número na tela, por que trabalhar com Double? Converta-o para string imediatamente.
let value = 123.456789let roundedString = String(format: "%.2f", value)print(roundedString) // "123.46"
// De volta para Double (se necessário)let roundedDouble = Double(roundedString) ?? 0.0Prós:
- Velocidade instantânea — sem operações matemáticas extras
- Quantidade garantida de casas decimais na saída
- Suporte a localização (separador decimal)
Contras:
- O resultado é uma string; para cálculos posteriores, é necessário converter de volta (perda de precisão)
- Não é adequado para arredondamento bancário (round half up por padrão)
Ideal para exibir preços, porcentagens, classificações — em qualquer lugar onde a precisão de ±0.01 não seja crítica.
Método 3: NSDecimalNumber — o rei da precisão financeira
Quando o dinheiro está em jogo, Double é o mal. Use NSDecimalNumber — ele armazena números em formato decimal sem erros de arredondamento.
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 (arredondamento bancário!)Prós:
- Controle total sobre o arredondamento — .plain, .down, .up, .b