一尘不染

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

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

我不明白为什么编译器从字典中打印值会有所不同?我使用的是Swift 3,Xcode8。这是错误还是优化内容的怪异方法?

编辑

更奇怪的是:

有些价值观过去了,有些则跌破了,有些则保持不变!1.1小于1.1000000000000001,而2.3大于2.2999999999999998,1.2仅为1.2


阅读 217

收藏
2020-07-07

共1个答案

一尘不染

如注释中已经提到的,a Double不能1.1精确存储值。Swift根据IEEE
754
标准使用(像许多其他语言一样)二进制浮点数。

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

1.100000000000000088817841970012523233890533447265625

与最接近的数目2.3可以被表示,作为一个Double

2.29999999999999982236431605997495353221893310546875

打印 该数字表示将其再次转换为带有小数表示的字符串,并且以不同的精度完成此操作,具体取决于您如何打印该数字。

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

另一方面,如果符合则print(x)呼叫。x.description``x``CustomStringConvertible

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

print(1.1.description) // 1.1
print(1.1.debugDescription) // 1.1000000000000001

从Swift源代码中,可以看到两者都使用Stubs.cpp中swift_floatingPointToString()
函数,并且参数分别设置为和。此参数控制数字到字符串转换的精度:Debug``false``true

int Precision = std::numeric_limits<T>::digits10;
if (Debug) {
  Precision = std::numeric_limits<T>::max_digits10;
}

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

  • digits10 –可以不改变地表示的小数位数,
  • max_digits10 –区分此类型的所有值所必需的小数位数。

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

2020-07-07