7
votes

Le moyen le plus rapide de calculer la somme des bits en octet

J'ai deux matrices d'octets de même longueur. Je dois effectuer une opération XOR entre chaque octet et après cette somme de calcul des bits.

Par exemple: P>

11110000^01010101 = 10100101 -> so 1+1+1+1 = 4


0 commentaires

9 Réponses :


1
votes

Les éléments suivants doivent faire

int BitXorAndSum(byte[] left, byte[] right) {
  int sum = 0;
  for ( var i = 0; i < left.Length; i++) { 
    sum += SumBits((byte)(left[i] ^ right[i]));
  }
  return sum;
}

int SumBits(byte b) {
  var sum = 0;
  for (var i = 0; i < 8; i++) {
    sum += (0x1) & (b >> i);
  }
  return sum;
}


3 commentaires

Qui résume les octets. J'ai compris l'OP signifie qu'il voulait que les bits soient résumés?


Salut. Merci de répondre. Mais j'ai besoin de la somme de bits, pas une somme simple. Voir mon exemple ci-dessus.


@winaed, @ bugai13 mon mauvais. Mis à jour.



3
votes

Comme je l'ai compris, vous voulez résumer les morceaux de chaque xor entre les octets gauche et droit.

for (int b = 0; b < left.Length; b++) {
  int num = left[b] ^ right[b];
  int sum = 0;

  for (int i = 0; i < 8; i++) {
    sum += (num >> i) & 1;
  }

   // do something with sum maybe?
}


1 commentaires

Si la performance est une contrepartie, vous souhaiterez peut-être précalculer la somme des bits pour chacune des 256 combinations d'octets possibles et les stocker dans une table de recherche. Je pense que cela donnerait un gain de performance, mais vous auriez besoin de le comparer.



3
votes

Je ne suis pas sûr si vous voulez dire que les octets ou les bits. Pour résumer les bits dans un octet, cela devrait fonctionner:

int nSum = 0;
for (int i=0; i<=7; i++)
{
   nSum += (byte_val>>i) & 1;
}


0 commentaires

9
votes

La manière la plus rapide serait probablement une table de recherche de 256 éléments ...

11110000^01010101 = 10100101 -> lut[165] == 4


1 commentaires

+1 Nabbits. Je voudrais juste poster cela - vos compétences parallèles implicites sont exceptionnelles :-)



12
votes

Utilisez une table de recherche. Il n'y a que 256 valeurs possibles après xoring, il ne s'agit donc pas de prendre beaucoup de temps. Contrairement à la solution de l'IZB, je ne suggérerais pas de placer manuellement toutes les valeurs dans - calculer la table de recherche une fois au démarrage en utilisant l'une des réponses de boucle.

Par exemple: < Pré> xxx

(vous pourrait-il en faire une méthode d'extension si vous vouliez vraiment ...)

Notez l'utilisation de octet [] dans le comtebitsafterxor méthode - vous pouvez pour le faire un iEnumerable pour plus de généralité, mais itération sur un tableau (qui est connu pour être un tableau au moment de la compilation) sera plus rapide. Probablement seulement microscopiquement plus rapide, mais hé, vous avez demandé le le plus rapide méthode :)

Je voudrais presque certainement effectivement exprimer comme < Pré> xxx

dans la vie réelle, mais voir qui fonctionne mieux pour vous.

Notez également le type de la variable xor comme un int . En fait, il n'y a pas d'opérateur xor défini pour valeurs d'octet , et si vous avez formulé xor a octet il compilerait toujours en raison de la nature du composé Les opérateurs d'affectation, mais cela effectuerait une distribution sur chaque itération - au moins dans l'IL. Il est tout à fait possible que le JIT s'en occupait de cela, mais il n'est pas nécessaire de le demander de :)


1 commentaires

Merci beaucoup pour votre réponse.



6
votes

Ceci est plus communément appelé compte de bit. Il y a littéralement des dizaines d'algorithmes différents pour le faire. ici est un site qui répertorie quelques-unes des méthodes les plus connues. Il y a même des instructions spécifiques à la CPU pour le faire.

théorogique, Microsoft pourrait ajouter un Bitarray.CountSetBitsbits qui se déroule avec le meilleur algorithme de cette architecture de la CPU. Pour moi, pour un, accueillerait une telle addition.


0 commentaires

0
votes

Une fonction générale pour compter les bits pourrait ressembler à: xxx

moins les 1-bits, plus cela fonctionne plus rapidement. Il bouclait simplement sur chaque octet et bascule le 1 bit le plus bas de cet octet jusqu'à ce que l'octet devienne 0. Les moulages sont nécessaires pour que le compilateur s'arrête de se plaindre du type élargissement et rétrécissement.

Votre problème pourrait alors être résolu en utilisant ceci: xxx


0 commentaires

1
votes

Il peut être réécrit comme ulong code> et utiliser dangereux code> le pointeur, mais octet code> est plus facile à comprendre:

static int BitCount(byte num)
{
    // 0x5 = 0101 (bit) 0x55 = 01010101
    // 0x3 = 0011 (bit) 0x33 = 00110011
    // 0xF = 1111 (bit) 0x0F = 00001111
    uint count = num;
    count = ((count >> 1) & 0x55) + (count & 0x55);
    count = ((count >> 2) & 0x33) + (count & 0x33);
    count = ((count >> 4) & 0xF0) + (count & 0x0F);
    return (int)count;
}


1 commentaires

A une faute de frappe dans le troisième calcul, le masque 0xf0 est incorrect lorsqu'il est fait après le décalage, doit utiliser un masque 0x0f.



0
votes

Une table de recherche devrait être le plus rapide, mais si vous voulez le faire sans une table de recherche, cela fonctionnera pour des octets en seulement 10 opérations.

public static int BitCount(byte value) {
    int v = value - ((value >> 1) & 0x55);
    v = (v & 0x33) + ((v >> 2) & 0x33);
    return ((v + (v >> 4) & 0x0F));
}


0 commentaires