模数2*Pi使用SSE/SSE2

Big*_*igA 3 c optimization sse simd

我仍然很擅长使用SSE,并且我正在尝试2*Pi为该命令的双精度输入实现模数1e8(其结果将被输入到一些矢量化的三角形计算中).

我目前对代码的尝试是基于以下的想法mod(x, 2*Pi) = x - floor(x/(2*Pi))*2*Pi:

#define _PD_CONST(Name, Val)                                            \
static const double _pd_##Name[2] __attribute__((aligned(16))) = { Val, Val }  

_PD_CONST(2Pi, 6.283185307179586);  /* = 2*pi  */  
_PD_CONST(recip_2Pi, 0.159154943091895); /* = 1/(2*pi)  */

void vec_mod_2pi(const double * vec, int Size, double * modAns)
{
    __m128d sse_a, sse_b, sse_c;
    int i;
    int k = 0;
    double t = 0;

    unsigned int initial_mode;
    initial_mode = _MM_GET_ROUNDING_MODE();

    _MM_SET_ROUNDING_MODE(_MM_ROUND_DOWN);

    for (i = 0; i < Size; i += 2)
    {
        sse_a = _mm_loadu_pd(vec+i);
        sse_b = _mm_mul_pd( _mm_cvtepi32_pd( _mm_cvtpd_epi32( _mm_mul_pd(sse_a, *(__m128d*)_pd_recip_2Pi) ) ), *(__m128d*)_pd_2Pi);
        sse_c = _mm_sub_pd(sse_a, sse_b);
        _mm_storeu_pd(modAns+i,sse_c);
    }

    k = i-2;
    for (i = 0; i < Size%2; i++)
    {
        t = (double)((int)(vec[k+i] * 0.159154943091895)) * 6.283185307179586;
        modAns[k+i] = vec[k+i] - t;
    }

    _MM_SET_ROUNDING_MODE(initial_mode);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,目前这还有很多NaN回答1.128e119(一些超出范围的0- > 2*Pi我的目标!).我怀疑我出错的地方在于我试图用来做双重转换的双转换floor.

任何人都可以建议我出错的地方以及如何改进它?

PS抱歉该代码的格式,这是我第一次在这里发布一个问题,似乎无法让它在代码块中给我空行以使其可读.

jan*_*neb 7

如果你想要任何精确度,简单的算法非常糟糕.有关准确的范围缩减算法,请参阅例如Ng等人,ARGUMENT REDUCTION FOR HUGE ARGUMENTS:Good to the Last Bit(现可通过Wayback Machine获得:2012-12-24)