swift:将string转换为double的问题

这是Xcode 7.3.1操作系统中的一个简单代码:

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

输出是惊喜: Optional(8.6999999999999993)

另外, Float(str)给出: 8.69999981

任何想法或这个家伙的原因? 任何提及这个将不胜感激。

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

编辑

在迅速:

(str为NSString).doubleValue返回8.7

现在,这是好的。 但是我的问题仍然没有得到完整的答案。 我们已经find了一个select,但为什么我们不能依靠双(“8.7”​​)。 请对此进行更深入的了解。

编辑2

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

所以,这个问题再次打开。

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

 let x = 8.7 

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

 8.699999999999999289457264239899814128875732421875 

有关这方面的更多信息可以在优秀的问答中find浮点math是否被破坏? 。


第二个问题是:为什么数字有时打印为“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 ,则print函数将调用其description属性并将结果输出到标准输出。
  • 否则,如果参数符合CustomDebugStringConvertible ,则打印函数调用是debugDescription属性,并将结果打印到标准输出。
  • 否则,使用其他一些机制。 (这里没有导入我们的目的。)

Doubletypes符合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源代码可以看出,两者最终都分别在Debug参数设置为falsetrue ,调用swift_floatingPointToString中的swift_floatingPointToString函数。 这控制了数字到string转换的精确度:

  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 – 区分此types的所有值所需的小数位数。

所以description创build一个小数位数较less的string。 该string可以转换为Double并返回给出相同结果的string。 debugDescription创build一个更多的十进制数字的string,以便任何两个不同的浮点值将产生不同的输出。


概要:

  • 大多数小数不能完全表示为二进制浮点值。
  • 浮点types的descriptiondebugDescription方法使用不同的精度来转换为string。 作为结果,
  • 打印一个可选的浮点值使用不同的精度进行转换,而不是打印一个非可选的值。

因此,在你的情况下,你可能想打印它之前打开可选:

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

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

另一种select可以是使用(NS)DecimalNumber而不是Double (例如货币金额),参见例如(NS)DecimalNumber Round Issue 。

我会用:

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

你可以使用这个代码可能是有用的。

 print(str.doubleValue)