这里有两个不同的问题。首先,正如评论中已经提到的那样,二进制浮点数不能
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.7print(x) // 8.7
是
Double("8.7")从不同8.7?一个比另一个更精确吗?
要回答这些问题,我们需要知道
print()函数的工作方式:
- 如果参数符合
CustomStringConvertible
,则打印函数将调用其description
属性并将结果打印到标准输出。 - 否则,如果参数符合
CustomDebugStringConvertible
,则打印函数调用isdebugDescription
属性,并将结果打印到标准输出。 - 否则,将使用其他机制。(出于我们的目的,此处未导入。)
的
Double类型符合
CustomStringConvertible,因此
let x = 8.7print(x) // 8.7
产生与输出相同的输出
let x = 8.7print(x.description) // 8.7
但是发生了什么
let str = "8.7"print(Double(str)) // Optional(8.6999999999999993)
Double(str)是 可选的 ,并
struct Optional不会 不 符合
CustomStringConvertible,而是要
CustomDebugStringConvertible。因此,print函数调用的
debugDescription属性
Optional,该属性又调用
debugDescription基础的
Double。因此,除了是可选的以外,数字输出与
let x = 8.7print(x.debugDescription) // 8.6999999999999993
但是
description和
debugDescription
浮点值之间有什么区别?从Swift的源代码中,可以看到两者最终都
swift_floatingPointToString
在Stubs.cpp中调用了
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创建一个具有较少十进制数字的字符串。该字符串可以转换为a
Double并返回给相同结果的字符串。
debugDescription创建具有更多十进制数字的字符串,以便任何两个不同的浮点值将产生不同的输出。
摘要:
- 大多数十进制数字不能完全表示为二进制浮点值。
- 浮点类型的
description
和debugDescription
方法使用不同的精度来转换为字符串。作为结果, - 打印 可选 浮点值与打印非可选值所使用的精度不同。
因此,根据您的情况,您可能希望在打印可选件之前将其拆开:
let str = "8.7"if let d = Double(str) { print(d) // 8.7}为了更好地控制,请使用
NSNumberFormatter该
%.<precision>f格式或对格式进行格式化。
另一种选择是使用
(NS)DecimalNumber而不是
Double



