Question

J'ai la fonction de goulot d'étranglement suivant.

typedef unsigned char byte;
void CompareArrays(const byte * p1Start, const byte * p1End, const byte * p2, byte * p3)
{
     const byte b1 = 128-30;
     const byte b2 = 128+30;
     for (const byte * p1 = p1Start; p1 != p1End; ++p1, ++p2, ++p3) {
        *p3 = (*p1 < *p2 ) ? b1 : b2;
    }
}

Je veux remplacer le code de C++ avec SSE2 fonctions intinsic. Je l'ai essayé _mm_cmpgt_epi8 mais utilisé signé comparer. Je besoin non signés comparer.

Y at-il astuce (SSE, SSE2, SSSE3) pour résoudre mon problème?

Remarque: Je ne veux pas utiliser dans ce cas multi-threading.

Était-ce utile?

La solution

Au lieu de compenser vos valeurs signées pour les rendre non signé, d'une manière un peu plus efficace serait de faire ce qui suit:

  • utilisation _mm_min_epu8 pour obtenir le min non signé de p1, p2
  • comparer cette min pour l'égalité avec p2 en utilisant _mm_cmpeq_epi8
  • le masque résultant sera désormais 0x00 pour les éléments p1 = p2
  • vous pouvez maintenant utiliser ce masque avec _mm_or_si128 et _mm_andc_si128 pour sélectionner les valeurs b1 / b2 appropriée

Notez que ceci est 4 instructions au total, par rapport à 5 en utilisant la méthode de comparaison offset + signée.

Autres conseils

Vous pouvez soustraire 127 de vos numéros, puis utilisez _mm_cmpgt_epi8

Oui, cela peut être fait en SIMD, mais il faudra quelques pas pour faire le masque.

Ruslik il a raison, je pense. Vous voulez XOR chaque composant avec 0x80 pour retourner le sens de la comparaison signé et non signé. _mm_xor_si128 (PXOR) vous permet de vous que - vous aurez besoin pour créer le masque comme un tableau char statique quelque part avant de le charger dans un registre SIMD. Ensuite _mm_cmpgt_epi8 vous obtient un masque et vous pouvez utiliser Bitwise ET (par exemple _mm_and_si128) pour effectuer un mouvement masqué.

Oui, SSE ne fonctionnera pas ici. Vous pouvez améliorer cette performance de code sur ordinateur multi-core en utilisant OpenMP:

void CompareArrays(const byte * p1Start, const byte * p1End, const byte * p2, byte * p3)
{
     const byte b1 = 128-30;
     const byte b2 = 128+30;

     int n = p1End - p1Start;
     #pragma omp parallel for
     for (int i = 0; i < n; ++p1, ++i) 
     {
        p3[i] = (p1[i] < p2[i]) ? b1 : b2;
     }
}

Malheureusement, la plupart des réponses ci-dessus sont incorrectes. Supposons un mot de 3 bits:

unsigned: 4 5 6 7 0 1 2 3 == signée: -4 -3 -2 -1 0 1 2 3 (bits: 101 110 111 100 000 001 010 011)

La méthode de Paul R est incorrect. Supposons que nous voulons savoir si 3> 2. min (3,2) == 2, ce qui suggère oui, la méthode fonctionne ici. Supposons maintenant que nous voulons savoir si, si 7> 2. La valeur 7 est -1 en représentation signée, donc min (-1,2) == -1, ce qui suggère à tort que 7 ne soit pas supérieure à 2 non signé.

La méthode par Andrey est incorrect. Supposons que nous voulons savoir si 7> 2, ou a = 7, et b = 2. La valeur 7 est -1 dans la représentation signée, de sorte que le premier terme (a> b) échoue, et la méthode suggère que 7 n'est pas plus à 2.

Cependant, le procédé par BJobnh, tel que corrigé par Alexey, est correcte. Il suffit de soustraire 2 ^ (n-1) à partir des valeurs, où n est le nombre de bits. Dans ce cas, nous soustraire 4 pour obtenir de nouvelles valeurs correspondant:

vieux signée: -4 -3 -2 -1 0 1 2 3 => new signée:. 0 1 2 3 -4 -3 -2 -1 == nouveau unsigned 0 1 2 3 4 5 6 7

En d'autres termes, unsigned_greater_than (a, b) est équivalent à signed_greater_than (a - 2 ^ (n-1), b - 2 ^ (n-1)).

utilisation pcmpeqb et la puissance avec vous.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top