Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

217
Visualizações
Swift lose precision in decimal formatting

I have an precision issue when dealing with currency input using Decimal type. The issue is with the formatter. This is the minimum reproducible code in playground:

let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.isLenient = true
formatter.maximumFractionDigits = 2
formatter.generatesDecimalNumbers = true

let text = "89806.9"
let decimal = formatter.number(from: text)?.decimalValue ?? .zero
let string = "\(decimal)"
print(string)

It prints out 89806.89999999999 instead of 89806.9. However, most other numbers are fine (e.g. 8980.9). So I don't think this is a Double vs Decimal problem.

Edit:

The reason I need to use the formatter is that sometimes I need to deal with currency format input:

let text = "$89,806.9"
let decimal = formatter.number(from: text)?.decimalValue ?? .zero
print("\(decimal)") // prints 89806.89999999999

let text2 = "$89,806.9"
let decimal2 = Decimal(string: text2)
print("\(decimal2)") // prints nil

over 4 years ago · Santiago Trujillo
4 Respostas
Responde à pergunta

0

I agree that this is a surprising bug, and I would open an Apple Feedback about it, but I would also highly recommend switching to Decimal(string:locale:) rather than a formatter, which will achieve your goal (except perhaps the isLenient part).

let x = Decimal(string: text)!
print("\(x)") // 89806.9

If you want to fix fraction digits, you can apply rounding pretty easily with * 100 / 100 conversions through Int. (I'll explain if it's not obvious how to do this; it works for Decimal, though not Double.)

over 4 years ago · Santiago Trujillo Relatório

0

If this is strictly a rendering issue and you're just looking to translate a currency value from raw string to formatted string then just do that.

let formatter = NumberFormatter()
formatter.numberStyle = .currency

let raw = "89806.9"

if let double = Double(raw),
   let currency = formatter.string(from: NSNumber(value: double)) {
    print(currency) // $89,806.90
}

If there is math involved then before you get to the use of string formatters, I would point you to Why not use Double or Float to represent currency? and How to round a double to an int using Banker's Rounding in C as great starting points.

over 4 years ago · Santiago Trujillo Relatório

0

Using the new FormatStyle seems to generate the correct result

let format = Decimal.FormatStyle
    .number
    .precision(.fractionLength(0...2))


let text = "89806.9"
let value = try! format.parseStrategy.parse(text)

Below is an example parsing a currency using the currency code from the locale

let currencyFormat = Decimal.FormatStyle.Currency
    .currency(code: Locale.current.currencyCode!)
    .precision(.fractionLength(0...2))

let amount = try! currencyFormat.parseStrategy.parse(text)

Swedish example:

let text = "89806,9 kr"
print(amount)

89806.9

Another option is to use the new init for Decimal that takes a String and a FormatStyle.Currency (or a Number or Percent)

let amount = try Decimal(text, format: currencyFormat)

and to format this value we can use formatted(_:) on Decimal

print(amount.formatted(currencyFormat))

Output (still Swedish):

89 806,9 kr

over 4 years ago · Santiago Trujillo Relatório

0

I get my response with double value and remove formatter.generatesDecimalNumbers line to get work.

let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.isLenient = true
formatter.maximumFractionDigits = 2
//formatter.generatesDecimalNumbers = true // I removed this line

let text = "$89806.9"
let double = formatter.number(from: text)?.doubleValue ?? .zero // converting as double or float
let string = "\(double)"
print(string) // 89806.9

let anotherText = "$0.1"
let anotherDouble = formatter.number(from: anotherText)?.doubleValue ?? .zero // converting as double or float
let anotherString = "\(anotherDouble)"
print(anotherString) // 0.1

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda