Efficient SSE FP `floor()` / `ceil()` / `round()` Rounding Functions Without SSE4.1?

牧云@^-^@ 提交于 2021-02-10 04:05:20

问题


How can I round a __m128 vector of floats up/down or to the nearest integer, like these functions?

  • Round - roundf()
  • Ceil - ceilf() or SSE4.1 _mm_ceil_ps.
  • Floor - floorf() or SSE4.1 _mm_floor_ps.

I need to do this without SSE4.1 roundps (_mm_floor_ps / _mm_ceil_ps / _mm_round_ps(x, _MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC). roundps can also truncate toward zero, but I don't need that for this application.

I can use SSE3 and earlier. (No SSSE3 or SSE4)

So the function declaration would be something like:

__m128 RoundSse( __m128 x ), __m128 CeilSse( __m128 x ) and __m128 FloorSse( __m128 x ).


回答1:


I'm posting the code from http://dss.stephanierct.com/DevBlog/?p=8:

It should be adopted into By Value form (I just removed the & from the code, not sure it is OK):

static inline __m128 FloorSse(const __m128 x) {
    __m128i v0 = _mm_setzero_si128();
    __m128i v1 = _mm_cmpeq_epi32(v0, v0);
    __m128i ji = _mm_srli_epi32(v1, 25);
    __m128i tmp = _mm_slli_epi32(ji, 23); // I edited this (Added tmp) not sure about it
    __m128 j = _mm_castsi128_ps(tmp); //create vector 1.0f // I edited this not sure about it
    __m128i i = _mm_cvttps_epi32(x);
    __m128 fi = _mm_cvtepi32_ps(i);
    __m128 igx = _mm_cmpgt_ps(fi, x);
    j = _mm_and_ps(igx, j);
    return _mm_sub_ps(fi, j);
}

static inline __m128 CeilSse(const __m128 x) {
    __m128i v0 = _mm_setzero_si128();
    __m128i v1 = _mm_cmpeq_epi32(v0, v0);
    __m128i ji = _mm_srli_epi32(v1, 25);
    __m128i tmp = _mm_slli_epi32(ji, 23); // I edited this (Added tmp) not sure about it
    __m128 j = _mm_castsi128_ps(tmp); //create vector 1.0f // I edited this not sure about it
    __m128i i = _mm_cvttps_epi32(x);
    __m128 fi = _mm_cvtepi32_ps(i);
    __m128 igx = _mm_cmplt_ps(fi, x);
    j = _mm_and_ps(igx, j);
    return _mm_add_ps(fi, j);
}

static inline __m128 RoundSse(const __m128 a) {
    __m128 v0 = _mm_setzero_ps();             //generate the highest value < 2
    __m128 v1 = _mm_cmpeq_ps(v0, v0);
    __m128i tmp = _mm_castps_si128(v1); // I edited this (Added tmp) not sure about it
    tmp = _mm_srli_epi32(tmp, 2); // I edited this (Added tmp) not sure about it
    __m128 vNearest2 = _mm_castsi128_ps(tmp); // I edited this (Added tmp) not sure about it
    __m128i i = _mm_cvttps_epi32(a);
    __m128 aTrunc = _mm_cvtepi32_ps(i);        // truncate a
    __m128 rmd = _mm_sub_ps(a, aTrunc);        // get remainder
    __m128 rmd2 = _mm_mul_ps(rmd, vNearest2); // mul remainder by near 2 will yield the needed offset
    __m128i rmd2i = _mm_cvttps_epi32(rmd2);    // after being truncated of course
    __m128 rmd2Trunc = _mm_cvtepi32_ps(rmd2i);
    __m128 r = _mm_add_ps(aTrunc, rmd2Trunc);
    return r;
}


inline __m128 ModSee(const __m128 a, const __m128 aDiv) {
    __m128 c = _mm_div_ps(a, aDiv);
    __m128i i = _mm_cvttps_epi32(c);
    __m128 cTrunc = _mm_cvtepi32_ps(i);
    __m128 base = _mm_mul_ps(cTrunc, aDiv);
    __m128 r = _mm_sub_ps(a, base);
    return r;
}


来源:https://stackoverflow.com/questions/54022478/efficient-sse-fp-floor-ceil-round-rounding-functions-without-sse

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!