Не могу понять как реализовать:
__m256d min(__m256d A, __m256d B, __m256d C, __m256d D)
{
__m256d result;
// result should contain 4 minimal values out of 16 : A[0], A[1], A[2], A[3], B[0], ... , D[3]
// moreover it should be result[0] <= result[1] <= result[2] <= result[2]
return result;
}
Любые идеи о том, как разумно использовать _mm256_min_pd
, _mm256_max_pd
и перетасовку/перестановку?
==================================================
Это то, где я зашел так далеко после:
__m256d T = _mm256_min_pd(A, B);
__m256d Q = _mm256_max_pd(A, B);
A = T; B = Q;
T = _mm256_min_pd(C, D);
Q = _mm256_max_pd(C, D);
C = T; D = Q;
T = _mm256_min_pd(B, C);
Q = _mm256_max_pd(B, C);
B = T; C = Q;
T = _mm256_min_pd(A, B);
Q = _mm256_max_pd(A, B);
A = T; D = Q;
T = _mm256_min_pd(C, D);
Q = _mm256_max_pd(C, D);
C = T; D = Q;
T = _mm256_min_pd(B, C);
Q = _mm256_max_pd(B, C);
B = T; C = Q;
имеем: A[0] ‹ B[0] ‹ C[0] ‹ D[0], A[1] ‹ B[1] ‹ C[1] ‹ D[1], A[2] ‹ B[ 2] ‹ C[2] ‹ D[2], A[3] ‹ B[3] ‹ C[3] ‹ D[3],
поэтому минимальное значение находится среди A, второе минимальное значение находится среди A или B, ... Не знаю, куда идти дальше ...
========================================================
Вторая идея заключается в том, что проблема сводится к самой себе, но с двумя входными элементами __m256. Если это можно сделать, то просто выполните min4(A,B) --> P, min4(C,D) --> Q, min4(P,Q) --> возвращаемое значение.
Хотя понятия не имею, как это сделать для двух векторов :)
=======================================================================
Обновление 2: проблема почти решена — следующая функция вычисляет 4 минимальных значения.
__m256d min4(__m256d A, __m256d B, __m256d C, __m256d D)
{
__m256d T;
T = _mm256_min_pd(A, B);
B = _mm256_max_pd(A, B);
B = _mm256_permute_pd(B, 0x5);
A = _mm256_min_pd(T, B);
B = _mm256_max_pd(T, B);
B = _mm256_permute2f128_pd(B, B, 0x1);
T = _mm256_min_pd(A, B);
B = _mm256_max_pd(A, B);
B = _mm256_permute_pd(B, 0x5);
A = _mm256_min_pd(A, B);
T = _mm256_min_pd(C, D);
D = _mm256_max_pd(C, D);
D = _mm256_permute_pd(D, 0x5);
C = _mm256_min_pd(T, D);
D = _mm256_max_pd(T, D);
D = _mm256_permute2f128_pd(D, D, 0x1);
T = _mm256_min_pd(C, D);
D = _mm256_max_pd(C, D);
D = _mm256_permute_pd(D, 0x5);
C = _mm256_min_pd(C, D);
T = _mm256_min_pd(A, C);
C = _mm256_max_pd(A, C);
C = _mm256_permute_pd(C, 0x5);
A = _mm256_min_pd(T, C);
C = _mm256_max_pd(T, C);
C = _mm256_permute2f128_pd(C, C, 0x1);
T = _mm256_min_pd(A, C);
C = _mm256_max_pd(A, C);
C = _mm256_permute_pd(C, 0x5);
A = _mm256_min_pd(A, C);
return A;
};
Остается только отсортировать значения в порядке возрастания внутри A перед возвратом.
__m128d
полезна для некоторых шагов, а может и нет. Если вас интересуют только 4 наименьших элемента, а не полная сортировка, может быть сложнее превзойти скалярный код с помощью сети сортировки SIMD. - person Peter Cordes   schedule 11.03.2016k
, где n также мало, когда гуглил алгоритм выбора simd. :/ - person Peter Cordes   schedule 12.03.2016