Décodage Zig Zag

Dans les tampons de protocole google Vue d'ensemble de l'encodage , ils introduisent quelque chose appelé "codage Zig Zag", cela prend des nombres signés, qui ont une petite magnitude, et crée une série de nombres non signés qui ont une petite magnitude.

Par exemple

Encoded => Plain
0 => 0
1 => -1
2 => 1
3 => -2
4 => 2
5 => -3
6 => 3

Et ainsi de suite. La fonction d'encodage qu'ils donnent pour cela est plutôt intelligente, c'est:

(n << 1) ^ (n >> 31) //for a 32 bit integer

Je comprends comment cela fonctionne, cependant, je ne peux pas pour la vie de moi comprendre comment inverser cela et le décoder retour dans les entiers 32 bits signés

23
demandé sur Charles 2010-02-06 01:32:11

6 réponses

Essayez celui-ci:

(n >> 1) ^ (-(n & 1))

Modifier:

Je poste un exemple de code pour la vérification:

#include <stdio.h>

int main()
{
  unsigned int n;
  int r;

  for(n = 0; n < 10; n++) {
    r = (n >> 1) ^ (-(n & 1));
    printf("%u => %d\n", n, r);
  }

  return 0;
}

J'obtiens les résultats suivants:

0 => 0
1 => -1
2 => 1
3 => -2
4 => 2
5 => -3
6 => 3
7 => -4
8 => 4
9 => -5
26
répondu 3lectrologos 2013-04-04 23:05:50

Que diriez-vous de

(n>>1) - (n&1)*n
3
répondu ergosys 2010-02-05 22:49:23

Voici encore une autre façon de faire la même chose, juste à des fins d'explication (vous devriez évidemment utiliser le One-liner de 3lectrologos).

Vous devez juste remarquer que vous xor avec un nombre qui est soit tous les 1 (équivalent à bitwise not) ou tous les 0 (équivalent à ne rien faire). C'est ce que (-(n & 1)) rapporte, ou ce qui est expliqué par la remarque de "décalage arithmétique" de google.

int zigzag_to_signed(unsigned int zigzag)
{
    int abs = (int) (zigzag >> 1);

    if (zigzag % 2)
        return ~abs;
    else
        return abs;
}

unsigned int signed_to_zigzag(int signed)
{
    unsigned int abs = (unsigned int) signed << 1;

    if (signed < 0)
        return ~abs;
    else
        return abs;
}

Donc, afin d'avoir beaucoup de 0 sur les positions les plus significatives, l'encodage en zigzag utilise le LSB comme bit de signe, et les autres bits comme valeur absolue (seulement pour les entiers positifs en fait, et la valeur absolue -1 pour les nombres négatifs en raison de la représentation du complément 2).

3
répondu Cimbali 2018-10-05 09:08:54

J'ai trouvé une solution, malheureusement ce n'est pas la beauté d'une ligne que j'espérais:

uint signMask = u << 31;
int iSign = *((Int32*)&signMask);
iSign >>= 31;
signMask = *((UInt32*)&iSign);

UInt32 a = (u >> 1) ^ signMask;
return *((Int32*)&a);
1
répondu Martin 2010-02-05 22:45:02

Après avoir manipulé la réponse acceptée proposée par 3lectrologos, Je ne pouvais pas la faire fonctionner en commençant par des longs non signés (en C # -- Erreur du compilateur). Je suis venu avec quelque chose de similaire à la place:

( value >> 1 ) ^ ( ~( value & 1 ) + 1 )

Cela fonctionne très bien pour toute langue qui représente des nombres négatifs dans le compliment de 2 (par exemple. Net).

1
répondu Imisnew2 2013-10-30 15:43:43

Je suis sûr qu'il y a des opérations bit à bit super efficaces qui le font plus rapidement, mais la fonction est simple. Voici une implémentation python:

def decode(n):
  if (n < 0):
    return (2 * abs(n)) - 1
  else:
    return 2 * n

>>> [decode(n) for n in [0,-1,1,-2,2,-3,3,-4,4]]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
-1
répondu aem 2010-02-05 22:45:43