【发布时间】:2019-07-12 00:03:41
【问题描述】:
试图从给定的 Double 值中创建一个 Decimal(或 NSDecimalNumber)用于 MONEY 计算我的应用程序。我在 Xcode 10 中使用 Swift 4。
但它会生成以下错误的值。
let doubleVal: Double = 56.203
Decimal(doubleVal) // Wrong Answer: 56.20299999999998976
Decimal.init(doubleVal) // Again Wrong Answer: 56.20299999999998976
如果我使用字符串初始化,那么正确。
Decimal(string: "56.203")! // Correct Decimal: 56.203
我记得在 java 中使用 BigDecimal 时如果调用具有双精度值的构造函数时遇到了同样的问题。例如。 new BigDecimal(double val)... 所以他们有这个额外的方法 valueOf BigDecimal.valueOf(amount); 可以从双精度中创建正确的 BigDecimal。
如何使用 Swift 从给定的 Double 值生成 Decimal?
【问题讨论】:
-
您的
let doubleVal: Double = 56.203已经“不精确”,因为二进制浮点数无法存储该精确值。比较stackoverflow.com/q/42781785/1187415 或stackoverflow.com/a/54621386/1187415。从字符串创建十进制数是正确的解决方案。 -
@JibW 浮点文字始终存储为
Double。因此,如果您将值声明为浮点字面量,则无法不丢失精度,并且以后能够在保持正确值的同时将其转换为Decimal。这是重复的,因为重复的目标确实解释了问题存在的原因以及如何克服它。 -
您的
doubleVal不包含确切的值 56.203,而是它的一些近似值。所以精度会丢失之前你创建小数。从字符串创建 Decimal 是一种可能的解决方案(正如您已经想到的那样)。更多可能的方法见stackoverflow.com/q/42781785/1187415。 -
请注意,Java 的 BigDecimal.valueOf() 首先将双精度转换为字符串,然后从该字符串创建 BigDecimal ...
-
除了使用
Decimal(string: "56.203")之外,另一种方法是指定指数和整数有效位,例如let value = Decimal(sign: .plus, exponent: -3, significand: 56203)