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
属性,并将结果打印到标准输出。 - 否则,使用其他一些机制。 (这里没有导入我们的目的。)
Double
types符合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
。 因此,打印函数调用Optional
的debugDescription
属性,该属性依次调用底层Double
的debugDescription
。 因此 – 除了是一个可选的 – 数字输出是一样的
let x = 8.7 print(x.debugDescription) // 8.6999999999999993
但是description
和debugDescription
之间的浮点值有什么区别? 从Swift源代码可以看出,两者最终都分别在Debug
参数设置为false
和true
,调用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的
description
和debugDescription
方法使用不同的精度来转换为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)