Swift 中的双倍 vs Float80 速度

Double vs Float80 speed in Swift

我听说x87 FPU是80位浮点数,所以即使我想用64位数字计算,它也会用80位计算然后转换。但是 Swift 在 x86-64DoubleFloat80 中哪个最快(计算算术时)?

虽然 x87 FPU 确实以 80 位 "extended" 精度在内部运行(至少,默认情况下;这是可定制的,实际上 32 位构建遵循 macOS ABI 集 64 位内部精度),针对 x86-64 的二进制文件不再使用 x87 FPU 指令。所有实现 64 位长模式扩展的 x86 芯片也支持 SSE2(事实上,这是 AMD64 规范所要求的),因此 64 位二进制文​​件始终可以假设支持 SSE2。因此,这就是用于实现浮点运算的方法,因为它更高效,也更容易为编译器优化。

即使是现代的 32 位构建也将 SSE2 视为最低限度,并且 当然 在 Macintosh 平台上,因为 SSE2 是在 Pentium 4 中引入的,它早于 Macintosh平台切换到 Intel x86 芯片。 Apple 机器中使用过的所有 x86 芯片都支持 SSE2。

所以不,您不会通过使用 80 位扩展精度类型看到任何性能改进。您不会从 x87 指令中看到任何性能改进,即使它们是由编译器生成的。而且您肯定不会在 x86-64 上看到任何性能改进,因为 SSE2 在硬件中支持最大 64 位精度。任何 80 位精度的操作都必须在软件中实现,或者强制智能编译器发出 x87 指令,这意味着您无法从 SSE2 的任何好的特性和有形的性能改进中受益。

Double 几乎总是[1] 在现代英特尔处理器上的 Float80 上至少与几乎任何语言一样快。在某些情况下它会明显更快:

  • Double 使用更少的内存;使用 Double 时算法的工作集可能适合缓存,但使用 Float80 时无法适合,从而导致严重的性能危害。

  • Double 可以利用 FMA 指令(在 Swift 中公开为 .add[ing]Product(x,y)fma() 自由函数),这有效地使最近的内核可达到的浮点吞吐量。

  • Double 可以由编译器自动矢量化。 Float80 上没有矢量指令。在可能的情况下,这可以为您提供高达 4 倍的加速。

  • sincospow 等数学函数在 Double 上比在 Float80 上更快.

还有其他一些使用 Double 的原因:它可以移植到非 x86 硬件,而 Float80 则不能,并且 Double 与 C 接口的互操作性比 Double 更容易Float80。您应该只在必要时使用 Float80,否则默认使用 Double

[1] 有一些小众案例 Float80 可以更快——如果算法在 Double 中反复下溢,但在 Float80 中保持在正常范围内,因为例子。这些很少见,通常不值得担心;更常见的是,您的算法也会在 Float80 中下溢,只需稍后进行几次迭代即可。