код simd, чтобы проверить, достаточно ли отличаются два двойных значения

Предположим, у меня есть два двойных значения, старое и новое.
Я хотел бы реализовать векторизованную функцию
который возвращает старый, если абс (х-у) < р, а новый иначе.

Вот код (test.cpp):

#include <emmintrin.h>
#include <iostream>

#define ARRAY_LENGTH 2

int main(void) {
// x = old value, y = new value, res = result
double *x, *y, *res;
posix_memalign((void **)&x, 16, sizeof(double) * ARRAY_LENGTH);
posix_memalign((void **)&y, 16, sizeof(double) * ARRAY_LENGTH);
posix_memalign((void **)&res, 16, sizeof(double) * ARRAY_LENGTH);

double p = 1e-4; // precision
__m128d sp = _mm_set1_pd(p);
x[0] = 1.5; y[0] = 1.50011; // x - old value, y - new value
x[1] = 2.; y[1] = 2.0000001;

__m128d sx = _mm_load_pd(x);
__m128d sy = _mm_load_pd(y);

// sign mask to compute fabs()
__m128d sign_mask = _mm_set1_pd(-0.);
// |x-y|
__m128d absval = _mm_andnot_pd(sign_mask, _mm_sub_pd(sx, sy) );
// mask of |x-y| < p
__m128d mask = _mm_cmplt_pd(absval, sp);
// sres = |x-y| < p ? x : y;
__m128d sres = _mm_or_pd(
_mm_and_pd(mask, sx), _mm_andnot_pd(mask, sy) );
_mm_store_pd(res, sres);
std::cerr << "res=" << res[0] << "," << res[1] << std::endl;
return 0;
}

Строить:

g++ -std=c++11 -msse4 test.cpp

Сначала мы вычисляем fabs (x-y), сравниваем с p и объединяем x, y, используя
полученная маска.

Кто-нибудь видит более эффективный способ кодирования этого? Благодарю.

2

Решение

Есть способ сделать этот алгоритм немного быстрее, но он может снизить точность:

// d = x - y;
__m128d diff = _mm_sub_pd(sx, sy);
// mask of |y - x| < p
__m128d mask = _mm_cmplt_pd(_mm_andnot_pd(sign_mask, diff), sp);
// sres = y + (|y - x| < p) ? (x - y) : 0;
__m128d sres = _mm_add_pd(sy, _mm_and_pd(mask, diff));

Другой способ — использование AVX и / или одинарной точности.

1

Другие решения

Других решений пока нет …