FPU,SSE单浮点.哪个更快?sub或mul

Ufn*_*d3r 3 c c++ floating-point assembly

告诉我哪一个更快:sub或者mul

我的目标平台是X86; FPU和SSE.

例:

'LerpColorSolution1'使用乘法.

'LerpColorSolution2'使用减法.

哪个更快?

void LerpColorSolution1(const float* a, const float* b, float alpha, float* out)
{
    out[0] = a[0] + (b[0] - a[0]) * alpha;
    out[1] = a[1] + (b[1] - a[1]) * alpha;
    out[2] = a[2] + (b[2] - a[2]) * alpha;
    out[3] = a[3] + (b[3] - a[3]) * alpha;
}

void LerpColorSolution2(const float* a, const float* b, float alpha, float* out)
{
    float f = 1.0f - alpha;
    out[0] = a[0]*f + b[0] * alpha;
    out[1] = a[1]*f + b[1] * alpha;
    out[2] = a[2]*f + b[2] * alpha;
    out[3] = a[3]*f + b[3] * alpha;
}
Run Code Online (Sandbox Code Playgroud)

谢谢大家 ;)

Ste*_*non 10

只是为了好玩:假设你(或你的编译器)矢量化你的两种方法(因为当然你会追逐性能),而你的目标是最近的x86处理器......

将"LerpColorSolution1"直接翻译成AVX指令如下:

VSUBPS  dst,   a,     b        // a[] - b[]
VSHUFPS alpha, alpha, alpha, 0 // splat alpha
VMULPS  dst,   alpha, dst      // alpha*(a[] - b[])
VADDPS  dst,   a,     dst      // a[] + alpha*(a[] - b[])
Run Code Online (Sandbox Code Playgroud)

该序列的长延迟链是sub-mul-add,在最新的Intel处理器上总延迟为3 + 5 + 3 = 11个周期.吞吐量(假设您只执行这些操作)受端口1利用率的限制,理论峰值为每两个周期一个LERP.(我故意忽略加载/存储流量,并专注于此处执行的数学运算).

如果我们看一下你的"LerpColorSolution2":

VSHUFPS alpha, alpha, alpha, 0 // splat alpha
VSUBPS  dst,   one,   alpha    // 1.0f - alpha, assumes "1.0f" kept in reg.
VMULPS  tmp,   alpha, b        // alpha*b[]
VMULPS  dst,   dst,   a        // (1-alpha)*a[]
VADDPS  dst,   dst,   tmp      // (1-alpha)*a[] + alpha*b[]
Run Code Online (Sandbox Code Playgroud)

现在,长延迟链是shuffle-sub-mul-add,其总延迟为1 + 3 + 5 + 3 = 12个周期; 吞吐量现在受端口0和1的限制,但每两个周期仍然有一个LERP的峰值.您需要为每个LERP操作停用一个额外的μop,这可能会使吞吐量略微降低,具体取决于周围环境.

所以你的第一个解决方案稍好一点; (这并不奇怪 - 即使没有这种分析细节,粗略的指导方针"更少的操作更好"是一个很好的经验法则).


Haswell显着倾向于第一种解决方案; 使用FMA,它在每个端口0,1和5上只需要一个μop,允许每个周期一个LERP的理论吞吐量; 虽然FMA也改进了解决方案2,但它仍然需要4μs,包括需要在端口0或1上执行的3μs.这将解决方案2限制为每1.5个循环一个LERP的理论峰值 - 比解决方案1慢50%.