首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >swift:将字符串转换为双重时的问题

swift:将字符串转换为双重时的问题
EN

Stack Overflow用户
提问于 2016-09-29 04:25:38
回答 2查看 7.9K关注 0票数 15

下面是Xcode 7.3.1操场中的简单代码:

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

输出是令人惊讶的:Optional(8.6999999999999993)

此外,Float(str)给出:8.69999981

对这家伙有什么想法或理由吗?如能提及这一点,将不胜感激。

另外,我应该如何将" 8.7“转换为双(或浮动)的8.7?

编辑

迅速:

(str as NSString).doubleValue返回8.7

现在,这没什么。但我的问题,仍然没有一个完整的答案。我们已经找到了另一种选择,但为什么我们不能依靠双倍(“8.7”)。请对此给予更深入的了解。

编辑2

("6.9“为NSString).doubleValue //打印6.9000000000000004

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-09-29 10:17:44

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let x = 8.7

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
8.699999999999999289457264239899814128875732421875

有关这一点的更多信息可以在优秀的Q&A 浮点数数学坏了吗?中找到。

第二个问题是:为什么这个数字有时印成"8.7“,有时又印成"8.6999999999999993"?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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,则print函数调用其description属性并将结果打印到标准输出。
  • 否则,如果参数符合CustomDebugStringConvertible,则打印函数调用是debugDescription属性,并将结果打印到标准输出。
  • 否则,使用其他机制。(不是为我们的目的进口的。)

因此,Double类型符合CustomStringConvertible

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let x = 8.7
print(x) // 8.7

产生的输出与

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let x = 8.7
print(x.description) // 8.7

但是发生了什么

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let str = "8.7"
print(Double(str)) // Optional(8.6999999999999993)

Double(str)是可选的,struct Optional不符合CustomStringConvertible,但符合CustomDebugStringConvertible。因此,print函数调用OptionalOptional属性,后者反过来调用底层DoubledebugDescription。因此--除了是可选的--数字输出与

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let x = 8.7
print(x.debugDescription) // 8.6999999999999993

但是对于浮点值而言,descriptiondebugDescription有什么区别呢?从Swift源代码可以看出,两者最终都在Stubs.cpp中调用Stubs.cpp函数,Debug参数分别设置为falsetrue。这控制数字到字符串转换的精度:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  int Precision = std::numeric_limits<T>::digits10;
  if (Debug) {
    Precision = std::numeric_limits<T>::max_digits10;
  }

有关这些常量的含义,请参见限制

  • digits10 -可以不改变地表示的十进制数,
  • max_digits10 -区分这种类型的所有值所需的十进制数。

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

摘要:

  • 大多数十进制数不能精确表示为二进制浮点值。
  • 浮点类型的descriptiondebugDescription方法对字符串的转换使用不同的精度。因此,
  • 打印可选浮点值与打印非可选值相比,转换使用不同的精度。

因此,在您的示例中,您可能希望在打印可选选项之前展开它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let str = "8.7"
if let d = Double(str) {
    print(d) // 8.7
}

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

另一种选择是使用(NS)DecimalNumber而不是Double (例如货币金额),参见迅速发行

票数 24
EN

Stack Overflow用户

发布于 2016-09-29 04:30:41

我会用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let doubleValue = NSNumberFormatter().numberFromString(str)?.doubleValue
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39770303

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文