[英]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
。 因此,打印函数调用Optional
的debugDescription
属性,后者又调用底层Double
的debugDescription
。 因此 - 除了是可选的 - 数字输出与
let x = 8.7
print(x.debugDescription) // 8.6999999999999993
但是浮点值的description
和debugDescription
之间有什么区别? 从 Swift 源代码可以看出,两者最终都调用了swift_floatingPointToString
中的swift_floatingPointToString
函数, 并将Debug
参数分别设置为false
和true
。 这控制数字到字符串转换的精度:
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
创建一个带有更多十进制数字的字符串,因此任何两个不同的浮点值都会产生不同的输出。
概括:
description
和debugDescription
方法使用不同的精度转换为字符串。 作为结果,因此,在您的情况下,您可能希望在打印之前解开可选项:
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.