【问题标题】:Create NSDecimalNumber or Decimal from a Double in Swift [duplicate]在 Swift 中从 Double 创建 NSDecimalNumber 或 Decimal [重复]
【发布时间】: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/1187415stackoverflow.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)

标签: swift decimal


【解决方案1】:

当 Swift 将基数为 10 的十进制数 (56.203) 转换为二进制数时,总会有一些 floating point error。正如您所说,您将这些用于货币计算,建议使用Int(向用户展示时可能乘以 1000?)。

【讨论】:

  • 这就是为什么这个 Decial 类是为了避免这些浮动点错误。字符串初始化工作正常,这是双重初始化有问题。当然应该有一个像 JAVA HAS 一样的适当方法来克服这个问题。
  • 如果乘以千则为 56202,这是错误的。正确的应该是 56203 ,当乘以 1000 时,是吗?
  • @JibW 实际上,即使在 Java 中你也有一个 double。 BigDecimal 然后做了一些数学魔术,使用近似值将双精度转换为 String(因此它不是精确的十进制值)。然后它从String 初始化BigDecimal。实际上,Swift 会有这个,但还没有。从String 初始化Decimal
猜你喜欢
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 2014-07-23
  • 1970-01-01
  • 2016-09-30
相关资源
最近更新 更多