Сравнение абсолютных значений с плавающей запятой в AVX - PullRequest
3 голосов
/ 11 июля 2020

Я хотел бы сравнить два вектора двойников на основе их абсолютных значений .

То есть векторного эквивалента следующего:

if (fabs(x) < fabs(y)) {
    ...
}

Is есть что-то лучше, чем просто взять абсолютное значение каждой стороны и продолжить _mm256_cmp_pd?

Интересуют все варианты AVX, AVX2 и AVX-512.

1 Ответ

3 голосов
/ 12 июля 2020

С AVX-512 вы можете сэкономить одну мкоп. Вместо 2x vandpd + vcmppd вы можете использовать vpternlogq + vpcmpuq. Обратите внимание, что в приведенном ниже решении предполагается, что числа не являются NaN.

Числа с плавающей запятой IEEE-754 обладают тем свойством nice, что они закодированы таким образом, что if x[62:0] integer_less_than y[62:0], затем как с плавающей точкой: abs(x)<abs(y).

Таким образом, вместо установки обоих битов знака на 0, мы можем скопировать бит знака x в бит знака y и сравните результат как целое число без знака. В (непроверенном) коде ниже для отрицательного x оба xi[63] и yi_sgnx[63] равны 1, а для положительного x оба xi[63] и yi_sgnx[63] равны 0. Таким образом, сравнение беззнаковых целых чисел фактически сравнивает xi[62:0] с yi[62:0], что как раз то, что нам нужно для сравнения abs(x)<abs(y).

Инструкция vpternlog подходит для копирования знакового бита, см. здесь или здесь . Не уверен, что константы z и 0xCA выбраны правильно.

__mmask8 cmplt_via_ternlog(__m512d x, __m512d y){
    __m512i xi        = _mm512_castpd_si512(x);                                       
    __m512i yi        = _mm512_castpd_si512(x);                                       
    __m512i z         = _mm512_set1_epi64(0x7FFFFFFFFFFFFFFFull);
    __m512i yi_sgnx   = _mm512_ternarylogic_epi64(z, yi, xi, 0xCA);
    return _mm512_cmp_epu64_mask(xi, yi_sgnx, 1);   /* _CMPINT_LT  */
}
...