C 内在效率 - 哪个更好?

C Intrinsics Efficiency - Which is better?

我目前正在优化一个程序,我需要计算 __m128 类型数字的倒数平方根。最初,在向量化之前(当数字是浮点数时),它只是 ans = 1.0f / sqrt(num),但现在我有 _mm_rsqrt_ps(num)。唯一的问题是,在处理较大的数据集时,这会使我的答案出现一定程度的偏差。

我想知道使用 _mm_div_ps()_mm_sqrt_ps 函数是否会更准确(尽管我预计需要更多时间),顺便说一句,如何分配 1.0f 输入 __m128.

谢谢。

I am left wondering if use of the _mm_div_ps() and _mm_sqrt_ps functions will be more accurate

当然,因为 rsqrtps 不是一个精确的运算,所以它的全部意义在于它是一个近似值。正如您可以在 intrinsics 指南的手册中阅读的那样,

The relative error for this approximation is:

|Relative Error| ≤ 1.5 ∗ 2−12

您可能会想将其解读为“大约前半部分有效位是正确的”,但比这更烦人的是,它喜欢在看似微不足道的情况下给出不准确的结果。例如,如果你输入 4,你可能会得到 0.499878(现在我电脑上的实际结果)。

这并不一定意味着您需要一个完整的平方根和 division。也许你会这样做,但通常将 rsqrtps 与优化步骤(未测试)结合使用就足够了:

__m128 y = _mm_rsqrt_ps(num);
__m128 yy = _mm_mul_ps(y, y);
__m128 hnum = _mm_mul_ps(num, _mm_set1_ps(0.5f));
__m128 threehalves = _mm_set1_ps(1.5f);
__m128 res = _mm_mul_ps(y, _mm_sub_ps(threehalves, _mm_mul_ps(yy, hnum)));

这比以前精确到大约两倍的位数。上面的技巧不再一定是一个胜利(取决于代码的使用方式),在 Core2 45nm 上,division 尤其是平方根非常慢,它很容易获胜,但从 IB 和更新的版本来看,它几乎是延迟的关系。即使在 Skylake 上,使用 sqrt 和 div 仍然会降低吞吐量。

上面的代码还展示了如何获取向量中的常量。