ios - swift:将字符串转换为 double 时出现问题

标签 ios swift cocoa cocoa-touch

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

var str = "8.7" 打印(双(str))

输出令人惊讶: 可选(8.69999999999999993)

此外,Float(str)给出:8.69999981

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

另外,我应该如何将“8.7”​​转换为 8.7 作为 Double(或 Float)?

编辑

快速:

(str as NSString).doubleValue 返回 8.7

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

编辑2

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

所以,问题再次出现。

最佳答案

这里有两个不同的问题。首先——正如已经提到的 注释 – 二进制 float 不能表示 号码8.7恰恰。 Swift 使用 IEEE 754 标准来表示 单精度和 double float ,并且如果您分配

let x = 8.7

那么最接近的可表示数字存储在 x 中,那就是

8.699999999999999289457264239899814128875732421875

有关这方面的更多信息可以在优秀的 问答Is floating point math broken? .

<小时/>

第二个问题是:为什么数字有时会打印为“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属性(property)和打印品 结果到标准输出。
  • 否则,将使用其他一些机制。 (这里没有为我们导入 目的。)

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 。因此打印函数调用 debugDescription Optional的属性(property),这反过来又 调用debugDescription底层证券Double 。 因此,除了可选之外,数字输出为 与

中的相同
let x = 8.7
print(x.debugDescription) // 8.6999999999999993

但是 description 之间有什么区别?和debugDescription 对于浮点值?从Swift源码可以看出 最终两者都调用 swift_floatingPointToString 函数位于 Stubs.cpp ,与 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漂浮的方法 点类型使用不同的精度来转换为 字符串。结果,
  • 打印可选浮点值与打印非可选值使用不同的转换精度。

因此,在您的情况下,您可能想要打开可选的 打印之前:<​​/p>

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

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

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

关于ios - swift:将字符串转换为 double 时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41038585/

相关文章:

swift - 在 Swift 中显示日期选择器的输入 - 分配给属性错误

c# - ExternalAccessory 输入流/输出流为空?

ios - 如何加载带有注释信息的 View Controller

ios - 自动调用用户位置

objective-c - Cocoa:假设传递 NSFilesPromisePboardType 的目标 URL 是文件 URL 是否安全?

objective-c - 检测用户何时截图

objective-c - NSUserDefaults 和绑定(bind)

ios - 我的应用程序会自动更新吗?还是用户需要在代码更新时更新应用程序?

ios - ASIHttpRequest S3 和适用于 iOS 的 AWS SDK 之间的区别?

ios - 如何快速从文件夹中获取随机图像?