理解NSDecimalRound行为



我试图使用NSDecimalRound(...Decimal值舍入。在大多数情况下,它的行为符合我的期望,但有时它会返回一个让我惊讶的值。在下面的例子中,第一个计算完成了我所期望的,即scale4,将2341.2143舍入到2341.2143(即相同的值)。第二次计算是相同的,除了现在被舍入的值是2341.2142(注意最后一位数字是2而不是3),这次返回的值是2341.2141,而我期望的值是2341.2142。在2341.2146中也发现了类似的行为,当四舍五入到4 d.p时,它变成了2341.2145。有人能解释为什么会发生这种情况吗?

// Working as expected... ////////////
var unrounded: Decimal = 2341.2143
var rounded = Decimal()
NSDecimalRound(&rounded, &unrounded, 4, .down)
print(rounded) // 2.2143
// A bit unexpected (to me at least) /////////
var unrounded: Decimal = 2341.2142
var rounded = Decimal()
NSDecimalRound(&rounded, &unrounded, 4, .down)
print(rounded) // 2.2141

问题来自于文字,它是Double,必须转换为Decimal。所以错误来自于转换:

var unrounded: Decimal = 2341.2143
//   ^-- decimal var    ^-- Double literal

如您所知,浮点编码容易出错。你可以在这里检查:

2341.2143 is encoded as 2341.21430000000009385985322296619415283203125  
rounded down makes 2341.2143
2341.2142 is encoded as 2341.21419999999989158823154866695404052734375 
rounded down makes 2341.2141 

您需要初始化Decimal以受益于更高的精度。不幸的是,这并不直观。例如,您可以使用以下命令,它的行为符合预期:

var unrounded3: Decimal = Decimal(sign:.plus, exponent:-4, significand:23412142)
var rounded3 = Decimal()
NSDecimalRound(&rounded3, &unrounded3, 4, .down)
print(rounded3)