NSDecimalNumber(x).intValue returns -2、0、15 和 199,取决于 x 中的小数位数 (x = 199.999...5)
NSDecimalNumber(x).intValue returns -2, 0, 15 and 199, depending on the amount of decimals in x (x = 199.999...5)
我们在我们的业务逻辑中发现了一个有趣的案例,它完全打破了我们的逻辑,我们不明白为什么 NSDecimalNumber
和 Decimal
会这样。
我的案例 playground 如下:
import Foundation
let pQuantity = Decimal(string: "0.2857142857142857")!
let pPrice = Decimal(string: "7.00000000000000035")!
let calced = NSDecimalNumber(decimal: pQuantity * pPrice * Decimal(integerLiteral: 100)) // 200
let decimal = calced.decimalValue // 199.9999999999999999999999999999995
let integer = calced.intValue // 0
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999999999999999999995")!).intValue // 0
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999995")!).intValue // 199
NSDecimalNumber(decimal: Decimal(string: "199.99999999999999995")!).intValue // 15
NSDecimalNumber(decimal: Decimal(string: "199.999999999999999995")!).intValue // -2
在上面的 playground 代码中,如果你向右滚动,你可以看到 return 值,如果你不想自己 运行 它。
我们需要将原始十进制值、数量和价格临时转换为整数,以计算将这些数量平均分配多少以产生美观的价格。然而,由于某种原因,在这种情况下我们不能,因为转换的初始步骤失败,生成 0
而不是 200
(是的,当前代码将生成 199
这是一个错误)。
为什么 NSDecimalNumber return 这些奇怪的值取决于小数位数,范围从 -2
到 199
?
我们的解决方案是在将内部计算放入 NSDecimalNumber
之前对其进行舍入,但我们首先想知道造成这种情况的原因。这是一个错误还是预期的错误,应该意识到它可能会发生?
这显然是一个基础错误,可能 the one mentioned by Martin R 在评论中。
我在 Playground (Swift 5) 中进行了试验,发现关于 int32Value
正确工作的错误的评论是正确的。
import Foundation
let pQuantity = Decimal(string: "0.2857142857142857")!
let pPrice = Decimal(string: "7.00000000000000035")!
let calced = NSDecimalNumber(decimal: pQuantity * pPrice * Decimal(integerLiteral: 100)) // 200
let decimal = calced.decimalValue // 199.9999999999999999999999999999995
let integer = calced.int32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999999999999999999995")!).uint32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999995")!).int32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.99999999999999995")!).int32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.999999999999999995")!).int32Value // 200
此外,如您所见,uint32Value
也可以正常工作。但是,64 位变体中的 none 有效。
如果您确定您的结果适合 Int32
,您可以将其用作解决方法,直到他们修复它为止,这可能永远不会,因为该错误已经存在一段时间了。
我们在我们的业务逻辑中发现了一个有趣的案例,它完全打破了我们的逻辑,我们不明白为什么 NSDecimalNumber
和 Decimal
会这样。
我的案例 playground 如下:
import Foundation
let pQuantity = Decimal(string: "0.2857142857142857")!
let pPrice = Decimal(string: "7.00000000000000035")!
let calced = NSDecimalNumber(decimal: pQuantity * pPrice * Decimal(integerLiteral: 100)) // 200
let decimal = calced.decimalValue // 199.9999999999999999999999999999995
let integer = calced.intValue // 0
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999999999999999999995")!).intValue // 0
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999995")!).intValue // 199
NSDecimalNumber(decimal: Decimal(string: "199.99999999999999995")!).intValue // 15
NSDecimalNumber(decimal: Decimal(string: "199.999999999999999995")!).intValue // -2
在上面的 playground 代码中,如果你向右滚动,你可以看到 return 值,如果你不想自己 运行 它。
我们需要将原始十进制值、数量和价格临时转换为整数,以计算将这些数量平均分配多少以产生美观的价格。然而,由于某种原因,在这种情况下我们不能,因为转换的初始步骤失败,生成 0
而不是 200
(是的,当前代码将生成 199
这是一个错误)。
为什么 NSDecimalNumber return 这些奇怪的值取决于小数位数,范围从 -2
到 199
?
我们的解决方案是在将内部计算放入 NSDecimalNumber
之前对其进行舍入,但我们首先想知道造成这种情况的原因。这是一个错误还是预期的错误,应该意识到它可能会发生?
这显然是一个基础错误,可能 the one mentioned by Martin R 在评论中。
我在 Playground (Swift 5) 中进行了试验,发现关于 int32Value
正确工作的错误的评论是正确的。
import Foundation
let pQuantity = Decimal(string: "0.2857142857142857")!
let pPrice = Decimal(string: "7.00000000000000035")!
let calced = NSDecimalNumber(decimal: pQuantity * pPrice * Decimal(integerLiteral: 100)) // 200
let decimal = calced.decimalValue // 199.9999999999999999999999999999995
let integer = calced.int32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999999999999999999995")!).uint32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.9999999999999995")!).int32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.99999999999999995")!).int32Value // 200
NSDecimalNumber(decimal: Decimal(string: "199.999999999999999995")!).int32Value // 200
此外,如您所见,uint32Value
也可以正常工作。但是,64 位变体中的 none 有效。
如果您确定您的结果适合 Int32
,您可以将其用作解决方法,直到他们修复它为止,这可能永远不会,因为该错误已经存在一段时间了。