Как сравнить __m128 типов? - PullRequest
8 голосов
/ 18 мая 2011
__m128 a;
__m128 b;

Как кодировать a != b?

что использовать: _mm_cmpneq_ps или _mm_cmpneq_ss?

Как обработать результат?

Можноне найти подходящих документов.

Ответы [ 3 ]

16 голосов
/ 18 мая 2011

Вы, вероятно, должны использовать _mm_cmpneq_ps.Однако интерпретация сравнений немного отличается от кода SIMD, чем от скалярного кода.Вы хотите проверить, что любой соответствующий элемент не равен?Или все соответствующие элементы не равны?

Чтобы проверить результаты 4 сравнений из _mm_cmpneq_ps, вы можете использовать _mm_movemask_epi8.

Обратите внимание, чтоСравнение значений с плавающей запятой для равенства или неравенства обычно плохая идея, за исключением очень специфических случаев.

__m128i vcmp = (__m128i)_mm_cmpneq_ps(a, b); // compare a, b for inequality
uint16_t test = _mm_movemask_epi8(vcmp); // extract results of comparison
if (test == 0xffff)
    // *all* elements not equal
else if (test != 0)
    // *some* elements not equal
else
    // no elements not equal, i.e. all elements equal

Для документации вам нужны эти два тома от Intel:

Руководство по разработке программного обеспечения для архитектур Intel® 64 и IA-32, том 2A: Справочник по наборам инструкций, AM

Руководство по разработке программного обеспечения для архитектур Intel® 64 и IA-32, том 2B: Справочник по наборам инструкций,NZ

1 голос
/ 08 февраля 2017

Ответ на этот вопрос также зависит от того, хотите ли вы иметь фактическое неравенство, в котором вы будете использовать что-то в соответствии с тем, что показало @PaulR:

bool fneq128_a (__m128 const& a, __m128 const& b)
{
    // returns true if at least one element in a is not equal to 
    // the corresponding element in b
    return _mm_movemask_ps(_mm_cmpeq_ps(a, b)) != 0xF;
}

или вы хотите использовать некоторые эпсилоныукажите, что элементы по-прежнему считаются «равными», если они не отличаются больше порогового значения:

bool fneq128_b (__m128 const& a, __m128 const& b, float epsilon = 1.e-8f)
{
    // epsilon vector
    auto eps = _mm_set1_ps(epsilon);
    // absolute of difference of a and b
    auto abd = _mm_andnot_ps(_mm_set1_ps(-0.0f), _mm_sub_ps(a, b));
    // compare abd to eps
    // returns true if one of the elements in abd is not less than 
    // epsilon
    return _mm_movemask_ps(_mm_cmplt_ps(abd, eps)) != 0xF;
}

Пример:

auto a = _mm_set_ps(0.0, 0.0, 0.0, 0.0);
auto b = _mm_set_ps(0.0, 0.0, 0.0, 1.e-15);
std::cout << fneq128_a(a, b) << ' ' << fneq128_b(a, b) << "\n";

Отпечатки:

 1 0
0 голосов
/ 02 апреля 2017

Рассмотрите возможность использования инструкции SSE4.1 ptest

if(_mm_testc_si128(_mm_castps_si128(a), _mm_castps_si128(b))) {
   /* equal */
} else {
   /* not equal */
} 

Эта является отдельной инструкцией.

...