NSDecimalNumber(x).intValue返回-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
的行为方式如此.
We found an interesting case in our business logic that totally breaks our logic and we don't understand why NSDecimalNumber
and Decimal
behaves the way it does.
我的案件游乐场如下:
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
如果您不想自己运行,则在上面的操场代码中,如果向右滚动,则可以看到返回值.
In the playground code above you can see the return value if you scroll to the right, if you don't want to run it yourselves.
在计算平均分配这些数量以产生美观价格时,我们需要暂时将原始十进制值,数量和价格转换为整数.但是,由于某种原因,由于转换的初始步骤失败,我们无法生成0
而不是200
(是的,当前代码将生成199
,这是一个错误),因此我们无法这样做.
We need to convert our raw decimal values, quantity and price, to ints temporarily when calculating how much to evenly split these quantities to produce nice-looking prices. We can't however for some reason in this case as the initial step of conversion fails, producing a 0
instead of 200
(and yes, the current code would produce 199
which is a bug).
为什么NSDecimalNumber根据小数位数(从-2
到199
)返回这些奇怪的值?
Why does the NSDecimalNumber return these weird values depending on the amount of decimals, ranging from -2
to 199
?
我们的解决方案是在将内部计算放入NSDecimalNumber
之前对其进行四舍五入,但是我们想知道开始的原因.是一个错误还是它是预期的,并且应该意识到它可能会发生?
Our solution would be to round the inner calculation before putting it into NSDecimalNumber
, but we'd like to know the cause of this to begin with. Is it a bug or is it expected and one should be aware that it might happen?
推荐答案
It's clearly a foundation bug, probably the one mentioned by Martin R in the comments.
我在Playground(Swift 5)中进行了实验,发现关于int32Value
正常工作的bug的评论是正确的.
I experimented in Playground (Swift 5) and found that the comment on that bug that int32Value
works correctly is true.
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位变体都不起作用.
Also, as you can see uint32Value
also works correctly. However, none of the 64 bit variants work.
只要您确定结果可以放入Int32
中,您就可以将其用作变通方法,直到他们修复它为止,考虑到该错误已经存在了一段时间,这可能永远不会解决.
Provided you are sure that your result will fit into an Int32
you can use that as a work around until they fix it, which is probably never, given that the bug has been outstanding for a while.
这篇关于NSDecimalNumber(x).intValue返回-2、0、15和199,具体取决于x中的小数位数(x = 199.999 ... 5)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!