NSDecimalNumber 用于 Swift 中的货币精度 [重复]

Posted

技术标签:

【中文标题】NSDecimalNumber 用于 Swift 中的货币精度 [重复]【英文标题】:NSDecimalNumber usage for precision with currency in Swift [duplicate] 【发布时间】:2018-02-05 23:09:19 【问题描述】:

我读过很多,NSDecimalNumber 是使用货币时使用的最佳格式。

但是,我仍然遇到浮点问题。

例如。

let a: NSDecimalNumber = 0.07 //0.07000000000000003
let b: NSDecimalNumber = 7.dividing(by: 100) //0.06999999999999999

我知道我可以使用 Decimal 并且 b 就是我所期望的:

let b: Decimal = 7 / 100 //0.07

我在我的应用程序中使用 Core Data。所以我坚持使用NSDecimalNumber。除非我想将很多 NSDecimalNumbers 转换为 Decimals

有人可以帮我弄到 0.07 吗?

【问题讨论】:

在向用户显示货币数据时,您应该使用NumberFormatter 只需使用 NumberFormatter 来显示您的号码。顺便说一句 0.06999999999999999 和 0.07 它实际上是相同的数字。顺便说一句,我会使用 Decimal 并在需要时将其转换为 NSDecimalNumber 问题是您分配的0.07 本身就是Double,它在NSDecimalNumber 发挥作用之前引入了精度问题。如果你想要0.07 的无损表示,你需要使用NSDecimalNumber 初始化器,它接受一个字符串"0.07" 比较***.com/questions/42781785/… @Rob:没有必要道歉或解释自己——我不会想到别的。 【参考方案1】:

问题在于您正在有效地进行浮点数学运算(存在忠实捕获Double 中的小数部分值的问题)并从Double 值创建Decimal(或NSDecimalNumber)已经引入了这种差异。相反,您希望在进行除法之前创建您的 Decimal 值(或者在获得小数 Double 值之前,即使是文字)。

因此,以下内容与您的示例等效,它正在构建0.07Double 表示(具有必然的限制),并且您最终得到的值不完全是0.07

let value = Decimal(7.0 / 100.0)                                // or NSDecimalNumber(value: 7.0 / 100.0)

而这不会遇到这个问题,因为我们将小数 7 除以小数 100

let value = Decimal(7) / Decimal(100)                           // or NSDecimalNumber(value: 7).dividing(by: 100) 

或者,在过程中创建0.07 值但避免Double 的其他方法包括使用字符串:

let value = Decimal(string: "0.07")                             // or NSDecimalNumber(string: "0.07")

或指定尾数/有效数和指数:

let value = Decimal(sign: .plus, exponent: -2, significand: 7)  // or NSDecimalNumber(mantissa: 7, exponent: -2, isNegative: false)

最重要的是,在使用Decimal(或NSDecimalNumber)时完全避免Double 表示,并且您不会遇到您描述的问题。

【讨论】:

说得真好。非常感谢!这对我很有帮助。 Decimal(7) 适用于像 7 这样的简单数字,但更准确的方法是使用 NSNumber(floatLiteral: 7).decimalValue。我使用Decimal 进行金融交易,在某些情况下,Decimal(7) 之类的方法不会产生准确的货币结果。虽然这种差异很小,但在金融交易中会加起来。 我建议也小心NSNumber(floatLiteral: x).decimalValue 模式,因为这需要x,伴随任何浮点问题,并且简单地捕获这些问题。作为一般规则,我仍然建议在使用非整数值时,使用上述模式之一。

以上是关于NSDecimalNumber 用于 Swift 中的货币精度 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中的 Java BigDecimal

NSDecimalNumber 问题

NSDecimalNumber用于精度准确的计算

如何在 NSDecimalNumber 中存储 1.66

NSDecimalNumber 如何判断是不是有小数部分

Swift 3 中的十进制到双精度转换