В итоге, проблема в том, что вы назвали spellDollars
с Double
, который он преобразовал в Decimal
.Вы можете сделать:
print(spellDollars(Decimal(string: "1019123.08")!))
Или
print(spellDollars(Decimal(sign: .plus, exponent: -2, significand: 101912308)))
И то и другое сработало бы без введения этого шума преобразования Double
в Decimal
.
Рассмотрим упрощенный пример:
let decimal1 = Decimal(floatLiteral: 1019123.08)
let decimal2 = Decimal(string: "1019123.08")!
let decimal3 = Decimal(sign: .plus, exponent: -2, significand: 101912308)
for value in [decimal1, decimal2, decimal3] {
print(value)
}
Будет выведено:
1019123.07999999979521019123,081019123.08
Чтобы понять, почему Double
в первом примере преобразуется в Decimal
значение 1019123.0799999997952
, я бы посоветовал вам обратиться к Что должен знать каждый компьютерный ученыйЧто касается арифметики с плавающей точкойон не может быть представлен в целочисленном формате или что-то в этом роде.
Я бы предложил разрезать узел Гордиана и не использовать арифметику NSDecimalNumber
для округления значений вручную.Используйте функцию NSDecimalRound
, например,
func spellDollars(_ amount: Decimal) -> String {
// instantiate formatters
let dollarsFormatter = NumberFormatter()
dollarsFormatter.numberStyle = .spellOut
let centsFormatter = NumberFormatter()
centsFormatter.minimumIntegerDigits = 2
// get dollars
var inputAmount = amount
var dollars = Decimal.zero
NSDecimalRound(&dollars, &inputAmount, 0, .down)
// get dollars and cents
var dollarsAndCents = Decimal.zero
NSDecimalRound(&dollarsAndCents, &inputAmount, 2, .plain)
// get cents
let cents = (dollarsAndCents - dollars) * 100
// build strings
let centsString = centsFormatter.string(for: cents)!
let dollarsString = dollarsFormatter.string(for: dollars)!.capitalized
return "\(dollarsString) and \(centsString)/100"
}