繁体   English   中英

swift:将字符串转换为双精度的问题

[英]swift: issue in converting string to double

这是 Xcode 7.3.1 playground 中的简单代码:

var str = "8.7" print(Double(str))

输出令人Optional(8.6999999999999993)Optional(8.6999999999999993)

另外, Float(str)给出: 8.69999981

对这些人有什么想法或理由吗? 对此的任何引用将不胜感激。

另外,我应该如何将“8.7”​​转换为 8.7 作为双精度(或浮点数)?

编辑

迅速:

(str as NSString).doubleValue 返回 8.7

现在,没关系。 但是我的问题仍然没有得到完整的答案。 我们找到了替代方案,但为什么我们不能依赖 Double("8.7")。 请对此有更深入的了解。

编辑 2

("6.9" as NSString).doubleValue // 打印 6.9000000000000004

所以,这个问题又打开了。

这里有两个不同的问题。 首先——正如评论中已经提到的——二进制浮点数不能精确地表示数字8.7 Swift 使用 IEEE 754 标准来表示单精度和双精度浮点数,如果您指定

let x = 8.7

然后将最接近的可表示数字存储在x ,即

8.699999999999999289457264239899814128875732421875

更多关于这方面的信息可以在优秀的问答中找到浮点数学是否被破坏? .


第二个问题是:为什么数字有时打印为“8.7”​​,有时打印为“8.6999999999999993”?

let str = "8.7"
print(Double(str)) // Optional(8.6999999999999993)

let x = 8.7
print(x) // 8.7

Double("8.7")8.7不同吗? 一个比另一个更精确吗?

要回答这些问题,我们需要知道print()函数是如何工作的:

  • 如果参数符合CustomStringConvertible ,则打印函数调用其description属性并将结果打印到标准输出。
  • 否则,如果参数符合CustomDebugStringConvertible ,则打印函数调用debugDescription属性并将结果打印到标准输出。
  • 否则,将使用某种其他机制。 (不是为了我们的目的在这里导入的。)

Double类型符合CustomStringConvertible ,因此

let x = 8.7
print(x) // 8.7

产生相同的输出

let x = 8.7
print(x.description) // 8.7

但是发生在

let str = "8.7"
print(Double(str)) // Optional(8.6999999999999993)

Double(str)可选的struct Optional符合CustomStringConvertible ,但CustomDebugStringConvertible 因此,打印函数调用OptionaldebugDescription属性,后者又调用底层DoubledebugDescription 因此 - 除了是可选的 - 数字输出与

let x = 8.7
print(x.debugDescription) // 8.6999999999999993

但是浮点值的descriptiondebugDescription之间有什么区别? 从 Swift 源代码可以看出,两者最终都调用了swift_floatingPointToString中的swift_floatingPointToString函数, 并将Debug参数分别设置为falsetrue 这控制数字到字符串转换的精度:

  int Precision = std::numeric_limits<T>::digits10;
  if (Debug) {
    Precision = std::numeric_limits<T>::max_digits10;
  }

有关这些常量的含义,请参阅http://en.cppreference.com/w/cpp/types/numeric_limits

  • digits10 – 可以不加变化地表示的十进制数字的数量,
  • max_digits10 – 区分此类型的所有值所需的十进制位数。

因此description创建了一个小数位数较少的字符串。 该字符串可以转换为Double并返回给相同结果的字符串。 debugDescription创建一个带有更多十进制数字的字符串,因此任何两个不同的浮点值都会产生不同的输出。


概括:

  • 大多数十进制数不能完全表示为二进制浮点值。
  • 浮点类型的descriptiondebugDescription方法使用不同的精度转换为字符串。 作为结果,
  • 打印可选浮点值使用的转换精度与打印非可选值不同。

因此,在您的情况下,您可能希望在打印之前解开可选项:

let str = "8.7"
if let d = Double(str) {
    print(d) // 8.7
}

为了更好地控制,请使用NSNumberFormatter或带有%.<precision>f格式的格式化打印。

另一种选择是使用(NS)DecimalNumber而不是Double (例如对于货币金额),参见例如Round Issue in swift

我会用:

let doubleValue = NSNumberFormatter().numberFromString(str)?.doubleValue

您可以使用此代码可能会有用。

print(str.doubleValue)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM