Giorgio
Giorgio

Reputation: 2210

NSNumberFormatter and .floor roundingMode

Can someone tell me why this happening?

let formatter = NumberFormatter.init()
formatter.numberStyle = .decimal
formatter.usesGroupingSeparator = false
formatter.roundingMode = .floor
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2

let v = 36
let scale = 10


let float = formatter.string(from: NSNumber(value: Float(v) / Float(scale)))!
let double = formatter.string(from: NSNumber(value: Double(v) / Double(scale)))!

print(float)    // 3.59
print(double)   // 3.60

When I use Float the result is 3.59 (wrong result in my opinion) and when I use Double the result is 3.60.

I know it is something related to .floor roundingMode, but i don't fully understand the reason.

Upvotes: 0

Views: 497

Answers (1)

Leo Dabus
Leo Dabus

Reputation: 236360

If you would like to preserve your fraction digits precision it is better to use Swift native Decimal type. That's what it is. You can use the Decimal init(sign: FloatingPointSign, exponent: Int, significand: Decimal) initializer and use your scale exponent and your value significand. Just make sure to negate its value:

extension SignedInteger {
    var negated: Self { self * -1 }
}

let v = 36
let scale = 10
let sign: FloatingPointSign = v >= 0 ? .plus : .minus
let exponent = Decimal(scale).exponent.negated
let significand = Decimal(v).significand
let decimal = Decimal.init(sign: sign, exponent: exponent, significand: significand)
let formatted = formatter.string(for: decimal)   // "3.60"

Upvotes: 1

Related Questions