0

I have this code that prints out an amount of money, but sometimes if the amount comes out to a multiple of 10 cents, like $22.50 or $189.20, the UI will chop off the last 0 to show $22.5 or $189.2?

@IBAction func btnCalPress(sender: AnyObject) {
    let tipPer = Double(PercentTip.text!)! / 100
    let billAmt = Double(BillAmount.text!)
    let salesTax = Double(SalesTax.text!)! / 100

    let tipAmt = Double(billAmt! * tipPer)
    let taxAmt = Double(billAmt! * salesTax)
    let totalAmt = tipAmt + taxAmt + billAmt!

    let tipAmountFormat = round(tipAmt * 100) / 100
    let taxAmountFormat = round(taxAmt * 100) / 100
    let totalPayFormat = round(totalAmt * 100) / 100

    TipAmount.text = "Tip: $\(tipAmountFormat)"
    TaxAmount.text = "Tax: $\(taxAmountFormat)"
    TotalAmount.text = "Total: $\(totalPayFormat)"
}
bneely
  • 9,083
  • 4
  • 38
  • 46
  • 1
    This is because 8 8.0 and 8.00 and 8.000 and 8.0000 are exactly the same Double. read this question for answer: http://stackoverflow.com/questions/24051314/precision-string-format-specifier-in-swift `String(format:"%.2f",tipAmountFormat)` – Daniel Krom May 14 '16 at 21:22
  • 1
    ***When dealing with currency, or numbers that require base ten, you should use NSDecimal/NSDecimalNumber.*** – jtbandes May 14 '16 at 22:39

2 Answers2

3

When dealing with currencies it's easier to rely on NSNumberFormatter, which happens to also deal with some currencies specificities.

Applied to your code it would be :

@IBAction func btnCalPress(sender: AnyObject) {
    let tipPer = Double(PercentTip.text!)! / 100
    let billAmt = Double(BillAmount.text!)!
    let salesTax = Double(SalesTax.text!)! / 100

    let tipAmt = Double(billAmt * tipPer)
    let taxAmt = Double(billAmt * salesTax)
    let totalAmt = tipAmt + taxAmt + billAmt

    let formatter = NSNumberFormatter()
    formatter.numberStyle = .CurrencyStyle

    let tipAmount = formatter.stringFromNumber(tipAmt)!
    let taxAmount = formatter.stringFromNumber(taxAmt)!
    let totalAmount = formatter.stringFromNumber(totalAmt)!

    TipAmount.text = "Tip: \(tipAmount)"
    TaxAmount.text = "Tax: \(taxAmount)"
    TotalAmount.text = "Total: \(totalAmount)"
}
Marcio
  • 1,979
  • 15
  • 25
0

Like @jtbandes says, you should use NSDecimalNumber when dealing with currencies, not Double or Float, otherwise you will lose precision.

Although floating point types can store large numbers:

print(FLT_MAX)    // 3.40282e+38
print(DBL_MAX)    // 1.79769313486232e+308

They are not suited to currencies because if you have an amount with a large number of decimal places, you will lose precision:

let amountString = "9999999999.000009"

let amountDouble = Double(amountString)!
print(amountDouble) 
// prints 9999999999.00001 notice how the .000009 was rounded up to .00001

let amountDecimalNumber = NSDecimalNumber(string: amountString)
print(amountDecimalNumber) // prints 9999999999.000009 no precision lost

When dealing with currencies, there is no excuse to lose precision, over millions of transactions, small rounding errors do add up! Only round for presentation.

let formatter = NSNumberFormatter()
formatter.numberStyle = .CurrencyStyle
let prettyAmount = formatter.stringFromNumber(amountDecimalNumber)
// prints $9,999,999,999.00
paulvs
  • 11,963
  • 3
  • 41
  • 66