为什么双打在字典中的打印方式不同?

Hon*_*ney 14 swift

let dic : [Double : Double] = [1.1 : 2.3, 2.3 : 1.1, 1.2 : 2.3]

print(dic)// [2.2999999999999998: 1.1000000000000001, 1.2: 2.2999999999999998, 1.1000000000000001: 2.2999999999999998]



let double : Double = 2.3
let anotherdouble : Double = 1.1

print(double) // 2.3
print(anotherdouble) // 1.1
Run Code Online (Sandbox Code Playgroud)

我不明白为什么编译器以不同方式打印字典中的值?我在Swift 3,Xcode 8上.这是一个错误或一些奇怪的优化方式或东西的方式吗?

编辑

更奇怪的是:

有些值过去了,有些值低于标准值,有些值保持不变!1.1小于1.1000000000000001而2.3大于2.2999999999999998,1.2仅为1.2

Mar*_*n R 14

正如评论中已经提到的,a Double无法1.1准确存储值.Swift根据IEEE 754 标准使用(像许多其他语言一样)二进制浮点数.

最接近的数目1.1可以被表示为Double

1.100000000000000088817841970012523233890533447265625
Run Code Online (Sandbox Code Playgroud)

并且最接近的数字2.3可以表示为Doubleis

2.29999999999999982236431605997495353221893310546875
Run Code Online (Sandbox Code Playgroud)

打印该数字意味着它再次转换为带有十进制表示的字符串,并且具有不同的精度,具体取决于您打印数字的方式.

从源代码HashedCollections.swift.gyb一个可以看到description的方法 Dictionary使用debugPrint()两个键和值,和debugPrint(x)打印的值x.debugDescription (如果x符合CustomDebugStringConvertible).

另一方面,如果符合,则print(x)调用.x.descriptionxCustomStringConvertible

所以,你看到的是输出不同descriptiondebugDescriptionDouble:

print(1.1.description) // 1.1
print(1.1.debugDescription) // 1.1000000000000001
Run Code Online (Sandbox Code Playgroud)

从夫特源代码的一个可以看到,无论使用swift_floatingPointToString() 功能Stubs.cpp,与Debug设置为参数falsetrue分别.此参数控制数字到字符串转换的精度:

int Precision = std::numeric_limits<T>::digits10;
if (Debug) {
  Precision = std::numeric_limits<T>::max_digits10;
}
Run Code Online (Sandbox Code Playgroud)

有关这些常量的含义,请参阅std :: numeric_limits:

  • digits10 - 可以无变化地表示的小数位数,
  • max_digits10 - 区分此类型的所有值所需的小数位数.

因此description创建一个十进制数较少的字符串.该字符串可以转换为a Double并返回到字符串,从而得到相同的结果. debugDescription创建一个具有更多十进制数字的字符串,以便任何两个不同的浮点值将产生不同的输出.