Do not use floats or doubles to represent the currency, for the exact (pun intended) this reason. Use NSDecimalNumber instead (see What data type Swift is used for currency ).
NSDecimalNumber makes some effort to use, but does base 10 arithmetic. To use it correctly, you need to read the API a bit. In particular, for rounding you need to provide NSDecimalNumberHandler (you can set a default value for use).
Good reading material:
I think the Playground is showing an unexpected result because it forces the internal value of NSDecimalNumber to Double before displaying it (I would welcome alternative or authoritative explanations because I'm curious). However, the internal representation must be correct.
Try this on your playground:
let myRoundingBehavior = NSDecimalNumberHandler(roundingMode: .RoundBankers, scale: 2, raiseOnExactness: true, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true) NSDecimalNumber.setDefaultBehavior(myRoundingBehavior) let integerPrice = NSDecimalNumber(mantissa: 987, exponent: -2, isNegative: false) integerPrice
Do not assume that Float is a more accurate representation of a number; it just works better here. If you keep your calculations (e.g. taxes, discounts, shipping, etc.) in the NSDecimalNumber area, they will be accurate.
Swift 3 / Xcode beta 1 bonus:
The behavior on the playground is still unchanged, but changes to the Great API Renaming Rodeo change the code above to:
let myRoundingBehavior = NSDecimalNumberHandler(roundingMode: .roundBankers, scale: 2, raiseOnExactness: true, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true)
The change here is that the global NSRoundingMode enumeration disappears and is replaced with the enum RoundingMode, which is a member of NSDecimalNumber.