如何对pow功能进行矢量化(带负底)?

时间:2017-09-24 12:47:19

标签: c++ c sse avx pow

我试图对功能进行矢量化(SSE / AVX)。在我找到的所有实现中,只需使用logexp进行矢量化:

pow(x, y) = exp(y * log(x))

它适用于正x,但由于负数的对数是一个复数,因此不会对负x起作用。是否有可能有效地矢量化战队,同时保持处理负x数字的能力?

2 个答案:

答案 0 :(得分:4)

这是一个通用的答案,没有充分利用你如何实际矢量化pow()的任何细节。

您可以检查基矢量的任何元素是否为负数,并在其上进行分支以在快速路径和慢速路径之间进行选择。

返回两个实部和虚部的向量,因此快速路径可以为虚部返回_mm_setzero_ps()。不想要虚构部分的来电者可以忽略它(而不是必须随机抽取以提取真实/虚构交替矢量的真实部分。)

因此,仅传递非负基础的呼叫者获得的行为几乎与矢量化真实版本一样快。

但是传递负面和非负面混合的来电者将获得慢速版本。如果你可以对慢速版本进行矢量化,那就完美了。

如果它不适用于正基础,那么当混合时你可以同时运行并混合(基于您检查的相同比较掩码,看你是否需要慢速版本)。 / p>

对于AVX版本,在内在名称中键入额外的256。 (并将检查更改为== 0xff,因为在movemask结果中还有4位。

// SSE4.1 for BLENDVPS
__m128  pow_complexresult(__m128 base, __m128 exp, __m128 &imag_result)
{
    __m128 negbase_vec = _mm_cmplt_ps(base, _mm_setzero_ps());
    unsigned negbase_mask = _mm_movemask_ps(negbase_vec);

    if (negbase_mask == 0) {               // all elements false
        imag_result = _mm_setzero_ps();
        return pow_nonegative(base, exp);   // fast path
    } else if (negbase_mask == 0xf) {      // all elements true
        return pow_negative(base, exp, imag_result);
    } else {
        // Only needed if pow_negative doesn't work for non-negative inputs.
        __m128 negpow = pow_negative(base, exp, imag_result);
        __m128 pospow = pow_simple(base, exp);
        imag_result = _mm_andn_ps(negbase_mask, imag_result);  // blend imaginary part
        return _mm_blendv_ps(pospow, negpow, negbase_vec);  // blend real part
    }
}

确保帮助函数内联,这样您就不会通过内存通过引用传递向量。

和/或将此包装内联到调用者中,这可以让检查针对常量向量进行优化。

我不认为Windows或System V ABI会在两个__m256寄存器中返回两个ymm向量的结构,因此第二个按引用arg可能是你最好的#&# 39;重新开始。

请注意,imag_result是最后一个arg,所以即使在Windows x64 ABI中,此函数仍然可以将其args在相同的寄存器中转发到pow_nonegative(base, exp);。虽然你想要它内联。

答案 1 :(得分:0)

好吧,如果你用负数做一些算术,你可以使用log()函数的主分支,它会在结果中引入一个虚构的+i*b*pi数字,然后在{{1因子.....只在你的指数exp(+i*b*pi)是一个精确整数的情况下映射到实数.....这不是你的一般情况,因为函数b声明为pow(3)类型....您可以解决此问题,编写一个检查负第一个参数的包装函数,并且只有在第二个参数是奇数时才给出否定值。隐藏实现细节作为练习让您完成...很容易实现double执行此检查并给出适当的结果。

但是如果指数double generalized_pow(double b, double e);参数将是整数...那么你最好实现fast power algorithm,这将给你答案可能比通过{{1}更快}和b函数。在Google中查看快速指数算法的实现。