Decimal precision correct?

I need to apply .bankers rounding mode but I'm getting some unexpected results when instiating some Decimals, I'm just wondering if this is a bug, expected behavior or what am I missing.


import Foundation


extension Decimal {
    
   func rounded(_ scale: Int, _ roundingMode: RoundingMode = .bankers) -> Decimal {
        var toRound = self
        var rounded = Decimal()
        NSDecimalRound(&rounded, &toRound, scale, roundingMode)
        return rounded
    }
}


var a: Decimal = NSDecimalNumber(floatLiteral: 6.422).decimalValue//6.422
print(a.rounded(1, .bankers))//6.4


var b: Decimal = NSDecimalNumber(floatLiteral: 6.4872).decimalValue//6.487200000000001024
print(b.rounded(2, .bankers))//6.49


var c: Decimal = NSDecimalNumber(floatLiteral: 6.997).decimalValue//6.997
print(c.rounded(2, .bankers))//7


var d: Decimal = NSDecimalNumber(floatLiteral: 6.6500).decimalValue//6.65
print(d.rounded(1, .bankers))//6.6


var e: Decimal = NSDecimalNumber(floatLiteral: 7.485).decimalValue//7.485000000000002048
var e2: Decimal = Decimal(floatLiteral: 7.485)//7.485000000000002048
print(e.rounded(2, .bankers))//7.49 wrong?, it should be 7.48
print(e2.rounded(2, .bankers))//7.49 wrong?, it should be 7.48


var f: Decimal = NSDecimalNumber(floatLiteral: 6.755000).decimalValue//6.755
print(f.rounded(2, .bankers))//6.76


var g: Decimal = NSDecimalNumber(floatLiteral: 8.995).decimalValue//8.994999999999997952
var g2: Decimal = Decimal(floatLiteral: 8.995)//8.994999999999997952
print(g.rounded(2, .bankers))//8.99 wrong?, it should be 9.00
print(g2.rounded(2, .bankers))//8.99 wrong?, it should be 9.00


var h: Decimal = NSDecimalNumber(floatLiteral:  6.6501).decimalValue//6.6501
print(h.rounded(1, .bankers))//6.7


var i: Decimal = NSDecimalNumber(floatLiteral:  7.4852007).decimalValue//7.4852007
print(i.rounded(2, .bankers))//7.49


var j: Decimal = NSDecimalNumber(floatLiteral:  19.57).decimalValue//19.57
print(j.rounded(2, .bankers))//19.57


Why is 7.485 actually 7.485000000000002048?

Why is 8.995 actually 8.994999999999997952?


Thank you in advance!

Replies

Problem when you transform first to Float, you have a precision effect ; hence the value is closer to 7.49 than 7.48.

So, the halfway effect does not play.


That seems to be normal behavior.

Problem when you transform first to Float, you have a precision effect

Yep. Consider this:

let n: Decimal = 7485
let d: Decimal = 1000
let e = n / d
print(e)    // -> 7.485
let r = e.rounded(2, .bankers)
print(r)    // -> 7.48

So if you construct your decimal precisely, you get the result you expect.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"