Calculer le hachage CRC32

14

Crédits

Ce défi provient de @miles .


Créez une fonction qui calcule le hachage CRC32 d'une chaîne d'entrée. L'entrée sera une chaîne ASCII de n'importe quelle longueur. La sortie sera le hachage CRC32 de cette chaîne d'entrée.

Explication

L'algorithme de CRC32 et d'autres CRC sont essentiellement les mêmes, donc seul CRC3 sera démontré ici.

Premièrement, vous avez le polynôme générateur, qui est en fait un entier 4 bits [n + 1] (serait 33 bits en CRC32).

Dans cet exemple, le polynôme générateur est 1101.

Ensuite, vous aurez la chaîne à hacher, ce qui serait le cas dans cet exemple 00010010111100101011001101.

00010010111100101011001101|000 (1)    append three [n] "0"s
   1101                        (2)    align with highest bit
00001000111100101011001101|000 (3)    XOR (1) and (2)
    1101                       (4)    align with highest bit
00000101111100101011001101|000 (5)    XOR (3) and (4)
     1101                      (6)    align with highest bit
00000011011100101011001101|000 (7)    XOR (5) and (6)
      1101                     (8)    align with highest bit
00000000001100101011001101|000 (9)    XOR (7) and (8)
          1101                 (10)   align with highest bit
00000000000001101011001101|000 (11)   XOR (9) and (10)
             1101              (12)   align with highest bit
00000000000000000011001101|000 (13)   XOR (11) and (12)
                  1101         (14)   align with highest bit
00000000000000000000011101|000 (15)   XOR (13) and (14)
                     1101      (16)   align with highest bit
00000000000000000000000111|000 (17)   XOR (15) and (16)
                       110 1   (18)   align with highest bit
00000000000000000000000001|100 (19)   XOR (17) and (18)
                         1 101 (20)   align with highest bit
00000000000000000000000000|001 (21)   XOR (19) and (20)
^--------REGION 1--------^ ^2^

Le reste obtenu à (21), lorsque la région 1 est nulle, ce qui est 001, serait le résultat du hachage CRC3.

Spécifications

  • Le polynôme générateur est 0x104C11DB7, ou 0b100000100110000010001110110110111, ou 4374732215.
  • L'entrée peut être une chaîne ou une liste d'entiers, ou tout autre format raisonnable.
  • La sortie doit être une chaîne hexadécimale ou simplement un entier, ou tout autre format raisonnable.
  • Les fonctions intégrées qui calculent le hachage CRC32 ne sont pas autorisées.

Objectif

Les règles standard pour le de s'appliquent.

Le code le plus court gagne.

Cas de test

input         output      (hex)
"code-golf"   147743960   08CE64D8
"jelly"       1699969158  65537886
""            0           00000000
Leaky Nun
la source
Si je comprends bien, cela consiste à faire la division polynomiale modulo 2 et à trouver le reste, c'est-à-dire l'analogue du mod dans la multiplication XOR .
xnor
1
Oui. Ce n'est cependant pas xnor modulo, c'est xor modulo.
Leaky Nun
Pour CRC32, ajoutez-vous d'abord 31 0?
xnor
Oui - - - - - - - - -
Leaky Nun
1
@KennyLau vous pouvez cingler des personnes avec leur nom, tout comme le chat.
Rɪᴋᴇʀ

Réponses:

12

Intel x86, 34 30 29 27 octets

Prend l'adresse de la chaîne terminée par zéro dans ESI et renvoie le CRC dans EBX:

31 db ac c1 e0 18 74 01 31 c3 6a 08 59 01 db 73 
06 81 f3 b7 1d c1 04 e2 f4 eb e7

Démontage (syntaxe AT&T):

00000000    xorl    %ebx, %ebx
00000002    lodsb   (%esi), %al
00000003    shll    $24, %eax
00000006    je      0x9
00000008    xorl    %eax, %ebx
0000000a    pushl   $8
0000000c    popl    %ecx
0000000d    addl    %ebx, %ebx
0000000f    jae     0x17
00000011    xorl    $0x4c11db7, %ebx
00000017    loop    0xd
00000019    jmp     0x2
0000001b

Intégration des suggestions de Peter Cordes pour économiser quatre octets supplémentaires. Cela suppose une convention d'appel où l'indicateur de direction pour les instructions de chaîne est effacé à l'entrée.

Intégration de la suggestion de Peter Ferrie d'utiliser littéralement push et pop pour charger une constante, économisant un octet.

Incorporation de la suggestion de Peter Ferrie de passer au deuxième octet d'une xorl %eax, %ebxinstruction qui est une retlinstruction, combinée à la modification de l'interface de la routine pour prendre une chaîne terminée par zéro au lieu de la longueur, économisant deux octets au total.

Mark Adler
la source
Utilisez une convention d'appel qui nécessite que l'indicateur de direction soit effacé à l'entrée, afin que vous puissiez enregistrer l' cldinsn (comme je l'ai fait dans ma réponse adler32 ). Est-il normal de permettre des conventions d'appel totalement arbitraires pour les réponses asm?
Peter Cordes
Quoi qu'il en soit, il semble que votre code fonctionnera comme du code machine x86-64, et vous pouvez utiliser la convention d'appel x86-64 SysV x32 pour prendre en compte ediet le pointeur esi(peut-être pas à extension zéro, donc peut-être fudge les choses et nécessite un Pointeur étendu zéro 64 bits). (x32 afin que vous puissiez utiliser en toute sécurité les mathématiques du pointeur 32 bits, mais avez toujours la convention d'appel register-args. Puisque vous n'utilisez pas inc, il n'y a aucun inconvénient au mode long.)
Peter Cordes
Avez-vous envisagé de conserver l' edxordre inverse des octets? bswap edxest seulement 2B. shr %edxest 2B, identique à votre décalage à gauche avec add %edx,%edx. Ce n'est probablement pas utile; À moins qu'il ne permette plus d'optimisation, vous économisez 3 milliards pour le shl $24, %eax, mais vous dépensez 4 milliards pour xor %eax,%eaxau début et bswap %edxà la fin. La mise à zéro d'Exo vous permet d'utiliser cdqà zéro %edx, donc dans l'ensemble c'est un lavage. Il fonctionnerait mieux, cependant: il évite le blocage / ralentissement du registre partiel à chaque itération d'écrire alpuis de lire eaxavec shl. : P
Peter Cordes
1
Vous avez confondu avec la question Adler-32, qui a une limite de longueur. Cette question n'a pas de limite de longueur explicite.
Mark Adler
1
Il pourrait y avoir un moyen de raccourcir cela avec l'instruction PCLMULQDQ. Cependant, son utilisation a tendance à nécessiter beaucoup de constantes, donc peut-être pas.
Mark Adler
4

Gelée, 34 octets

l2_32Ḟ4374732215æ«^
Oḅ⁹æ«32Çæ»32$¿

Essayez-le en ligne!

Leaky Nun
la source
4

Rubis, 142 octets

Fonction anonyme; prend une chaîne en entrée, retourne un entier.

->s{z=8*i=s.size;r=0;h=4374732215<<z
l=->n{j=0;j+=1 while 0<n/=2;j}
s.bytes.map{|e|r+=e*256**(i-=1)};r<<=32
z.times{h/=2;r^=l[h]==l[r]?h:0}
r}
Encre de valeur
la source
2
Pouvez-vous changer votre nom afin que les gens puissent nous distinguer? XD
Leaky Nun
2
@KennyLau devez-vous être si pointilleux ... OK bien
Value Ink
Je plaisantais juste xd
Leaky Nun
4

Gelée , 23 octets

ḅ⁹Bµ4374732215B×ḢḊ^µL¡Ḅ

L'entrée se présente sous la forme d'une liste d'entiers. Essayez-le en ligne! ou vérifiez tous les cas de test .

Comment ça fonctionne

Bien que Jelly ait XOR au niveau du bit, le remplissage de l'entrée avec des zéros et l'alignement du polynôme avec le chiffre binaire le plus significatif rend cette approche, qui utilise des listes de bits à la place, un peu plus courte.

ḅ⁹Bµ4374732215B×ḢḊ^µL¡Ḅ  Main link. Argument: A (list of bytes)

ḅ⁹                       Convert A from base 256 to integer.
  B                      Convert the result to binary, yielding a list.
   µ                     Begin a new, monadic chain. Argument: B (list of bits)
    4374732215B          Convert the integer to binary, yielding a list.
                Ḣ        Pop and yield the first, most significant bit of B.
               ×         Multiply each bit in the polynomial by the popped bit.
                 ^       Compute the element-wise XOR of both lists.
                         If one of the lists is shorter, the elements of the other
                         lists do not get modified, thus avoiding the necessity
                         of right-padding B with zeroes.
                  µ      Convert the previous chain into a link.
                   L¡    Execute the chain L times, where L is the number of bits
                         in the original bit list.
                     Ḅ   Convert from binary to integer.
Dennis
la source
3

CJam, 37 36 octets

q256b32m<{Yb4374732215Yb.^Yb_Yb32>}g

Testez-le ici.

Explication

q               e# Read input.
256b            e# Convert to single number by treating the character codes
                e# as base-256 digits.
32m<            e# Left-shift the number by 32 bits, effectively appending 32
                e# zeros to the binary representation.
{               e# While the condition on top of the stack is truthy...
  Yb            e#   Convert the number to base 2.
  4374732215Yb  e#   Convert the polynomial to base 2.
  .^            e#   Take the bitwise XOR. If the number is longer than the
                e#   polynomial, the remaining bits will be left unchanged.
  Yb            e#   Convert the list back from base 2, effectively stripping
                e#   leading zeros for the next iteration.
  _             e#   Duplicate the result.
  Yb            e#   Convert back to base 2.
  32>           e#   Remove the first 32 bits. If any are left, continue the loop.
}g
Martin Ender
la source
q256bYb_,{(4374732215Ybf*1>.^}*Ybenregistre quelques octets.
Dennis
@Dennis C'est vraiment intelligent, n'hésitez pas à en faire une réponse distincte. :)
Martin Ender
3

Pyth, 28 octets

uhS+GmxG.<C"Á·"dlhG.<Cz32

Essayez-le en ligne: Démonstration ou suite de tests

Explication:

uhS+GmxG.<C"..."dlhG.<Cz32   implicit: z = input string
                      Cz     convert to number
                    .<  32   shift it by 32 bits
u                            apply the following expression to G = ^,
                             until it get stuck in a loop:
     m           lhG            map each d in range(0, log2(G+1)) to:
          C"..."                   convert this string to a number (4374732215)
        .<      d                  shift it by d bits
      xG                           xor with G
   +G                           add G to this list
 hS                             take the minimum as new G
Jakube
la source
2

JavaScript (ES6), 180 octets

f=(s,t=(s+`\0\0\0\0`).replace(/[^]/g,(c,i)=>(c.charCodeAt()+256*!!i).toString(2).slice(!!i)))=>t[32]?f(s,t.replace(/.(.{32})/,(_,m)=>(('0b'+m^79764919)>>>0).toString(2))):+('0b'+t)

L'absence d'un opérateur XOR 33 bits, ou même d'un opérateur XOR 32 bits non signé, est inutile.

Neil
la source
1

CJam, 33 octets

q256bYb_,{(4374732215Ybf*1>.^}*Yb

L'entrée se présente sous la forme d'une chaîne. Essayez-le en ligne!

Comment ça fonctionne

q                                  Read all input from STDIN.
 256bYb                            Convert it from base 256 to base 2.
       _,{                   }*    Compute the length and repeat that many times:
          (                          Shift out the first bit.
           4374732215Yb              Convert the integer to base 2.
                       f*            Multiply each bit by the shifted out bit.
                         1>          Remove the first bit.
                           .^        Compute the element-wise XOR of both lists.
                                     If one of the lists is shorter, the elements
                                     of the other lists do not get modified, thus
                                     avoiding the necessity of right-padding B with
                                     zeroes.
                               Yb  Convert the final result from base 2 to integer.
Dennis
la source