Performance 每个浮点运算需要相同的时间吗?

Performance 每个浮点运算需要相同的时间吗?,performance,floating-point,cpu-architecture,micro-optimization,alu,x86,Performance,Floating Point,Cpu Architecture,Micro Optimization,Alu,X86,我相信无论操作数有多大,整数加法或减法总是需要相同的时间。ALU输出稳定所需的时间可能因输入操作数而异,但利用ALU输出的CPU组件将等待足够长的时间,以便在相同的周期内处理任何整数操作。 (ADD、SUB、MUL和DIV所需的周期将不同,但无论输入操作数如何,ADD都将采用相同的周期。) 浮点运算也是这样吗 我正在尝试实现一个包含大量浮点运算的程序。我想知道缩放我正在处理的数字是否有助于加快运行时间。TL:DR:避免非规范数字,你就没事了。如果不需要逐渐下溢,请在x86 MXCSR中将非规范值

我相信无论操作数有多大,整数加法或减法总是需要相同的时间。ALU输出稳定所需的时间可能因输入操作数而异,但利用ALU输出的CPU组件将等待足够长的时间,以便在相同的周期内处理任何整数操作。 (ADD、SUB、MUL和DIV所需的周期将不同,但无论输入操作数如何,ADD都将采用相同的周期。)

浮点运算也是这样吗


我正在尝试实现一个包含大量浮点运算的程序。我想知道缩放我正在处理的数字是否有助于加快运行时间。

TL:DR:避免非规范数字,你就没事了。如果不需要逐渐下溢,请在x86 MXCSR中将非规范值设置为零,并将其刷新为零位,或将其他体系结构设置为等效值。在大多数CPU中,产生一个非规范化结果会捕获到微码,因此需要数百个周期而不是5个周期

有关x86CPU的详细信息,请参阅,以及标记wiki


这取决于您的CPU,但典型的现代FPU在这方面都是相似的


除非规范化操作数外,add/sub/mul操作的延迟/吞吐量不依赖于典型的现代FPU(包括x86、ARM和其他)。它们通常是完全流水线的,但具有多周期延迟(即,如果输入准备就绪,新的MUL可以在每个周期开始执行),这使得可变延迟不便于无序调度

可变延迟意味着两个输出将在同一个周期内准备就绪,无法实现完全管道化的目的,并且使调度程序无法像处理已知但混合延迟指令/UOP时通常那样可靠地避免冲突。(,但同样的想法也适用于ALU本身,它需要一个额外的缓冲区,直到它能够传递它已经准备好的所有结果。)

以高性能高端产品为例:英特尔Haswell

  • mulpd
    (标量、128b或256b双精度向量):5c延迟,每1c吞吐量两个(两个单独的ALU)
  • FMA:5c延迟,每1c吞吐量两个
  • addpd
    /
    subpd
    :3c延迟,每1c吞吐量一个。(但add装置与其中一个mul/FMA装置位于同一端口上)
  • divpd
    (标量或128b向量):10-20c延迟,每8-14c吞吐量一个。(与其中一个mul/FMA装置位于同一端口)。对于256b向量较慢(div ALU不是全宽)。与add/sub/mul不同,
    float
    s的速度稍快一些
  • sqrtpd
    :16c延迟,每8-14c吞吐量一个。同样不是全宽,对于
    浮动
    ,速度更快
  • rsqrtps
    (快速非常近似,仅适用于
    float
    ):5c延迟,每1c吞吐量一个

div/sqrt是例外:它们的吞吐量和延迟取决于数据

div或sqrt没有快速并行算法。需要某种迭代计算,因此完全流水线需要为每个流水线阶段复制大量非常相似的硬件。尽管如此,现代Intel x86 CPU仍采用部分流水线div和sqrt,其交互吞吐量小于延迟

与mul相比,div/sqrt的吞吐量要低得多(~1/10或更差),延迟要高得多(~2到4倍)。现代FPU中div/sqrt单元的不完全流水线性质意味着它可以是可变延迟,而不会在ALU输出端口造成太多冲突

SSE/AVX不将sin/cos/exp/log作为单个指令实现;数学库应该自己编写代码

甚至在SSE存在之前,许多优秀的数学库都没有使用这两种方法;它在所有现有的实现上都是微编码的,因此内部实现使用相同的80位add/sub/mul/div/sqrt硬件,您可以用简单的指令进行编程;没有专用的
fsin
硬件(或者至少没有太多;可能是一个查找表)。对于大多数其他trig/Preferential x87函数(如
fyl2x
)也是如此

如果有一些专用的
fsin
硬件就好了,因为对于非常接近Pi/2倍数的输入,范围缩小到+/-Pi/2确实可以从更高的精度中获益
fsin
使用与从
fldpi
获得的相同的80位Pi常量(带有64位尾数)。这是与Pi的精确值最接近的可表示的
long double
,接下来的两个二进制数字碰巧为零,因此它实际上精确到66位。但它仍然会导致。(布鲁斯·道森(Bruce Dawson)关于浮点的系列文章非常优秀,如果你要写一些浮点代码,一定要读它们。

英特尔无法在不破坏与现有CPU的数字兼容性的情况下提高x87
fsin
的范围缩减精度。对于不同的x86 CPU来说,当使用相同的输入运行相同的指令时,它会给出数字上相同的结果,这是非常有用的。在软件中,您可以使用扩展精度浮点进行范围缩减,如所谓的四精度(但仍然只有指数范围
双精度
)。使用SSE2压缩双精度指令可以相当有效地实现double-double。
fsin
的SSE2库实现可能追求速度而非精度,并与x87硬件进行相同的权衡;仅使用常规的
double
Pi常数缩小范围,在最坏的情况下会导致较大的错误。对于某些用例来说,这是一个有效的选择,这也是软件的一大优势:您可以为您的用例选择正确的软件实现

IDK关于x87 exp或日志指令,如。它们是微型计算机