Calcola l'hash CRC32


14

Titoli di coda

Questa sfida è nata da @miles .


Creare una funzione che calcola l'hash CRC32 di una stringa di input. L'input sarà una stringa ASCII di qualsiasi lunghezza. L'output sarà l'hash CRC32 di quella stringa di input.

Spiegazione

L'algoritmo di CRC32 e altri CRC sono essenzialmente gli stessi, quindi solo CRC3 verrà dimostrato qui.

Innanzitutto, hai il polinomio del generatore, che in realtà è un numero intero [n + 1] a 4 bit (sarebbe 33 bit in CRC32).

In questo esempio, il polinomio del generatore è 1101.

Quindi, avrai la stringa da sottoporre a hash, che in questo esempio sarebbe 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^

Il resto ottenuto a (21), quando la regione 1 è zero, ovvero 001sarebbe il risultato dell'hash CRC3.

Specifiche

  • Il polinomio del generatore è 0x104C11DB7, o 0b100000100110000010001110110110111, o 4374732215.
  • L'input può essere una stringa o un elenco di numeri interi o qualsiasi altro formato ragionevole.
  • L'output può essere una stringa esadecimale o solo un numero intero o qualsiasi altro formato ragionevole.
  • Gli incorporati che calcolano l'hash CRC32 non sono consentiti.

Obbiettivo

Si applicano le regole standard per il .

Vince il codice più corto.

Casi test

input         output      (hex)
"code-golf"   147743960   08CE64D8
"jelly"       1699969158  65537886
""            0           00000000

Se ho capito bene, questo sta facendo la divisione polinomiale modulo 2 e sta trovando il resto, cioè l'analogo della mod nella moltiplicazione XOR .
xnor

1
Sì. Questo non è xnor modulo, questo è xor modulo.
Leaky Nun,

Per CRC32, aggiungi prima 31 0?
xnor

Sì - - - - - - - - -
Leaky Nun

1
@KennyLau puoi fare il ping delle persone con il loro nome, proprio come la chat.
R

Risposte:


12

Intel x86, 34 30 29 27 byte

Accetta l'indirizzo della stringa con terminazione zero in ESI e restituisce il CRC in 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

Disassemblaggio (sintassi 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

Incorporando suggerimenti di Peter Cordes per salvare altri quattro byte. Ciò presuppone una convenzione di chiamata in cui il flag di direzione per le istruzioni di stringa viene cancellato all'entrata.

Incorporando il suggerimento di Peter Ferrie di usare push letteral e pop per caricare una costante, salvando un byte.

Incorporando il suggerimento di Peter Ferrie di saltare al secondo byte di xorl %eax, %ebxun'istruzione che è retlun'istruzione, combinato con la modifica dell'interfaccia della routine per prendere una stringa con terminazione zero invece della lunghezza, risparmiando due byte in totale.


Usa una convenzione di chiamata che richiede che il flag di direzione venga cancellato all'entrata, in modo da poter salvare l' cldinsn (come ho fatto nella mia risposta adler32 ). È prassi normale consentire convenzioni di chiamata totalmente arbitrarie per le risposte asm?
Peter Cordes,

Ad ogni modo, sembra che il tuo codice funzionerà come codice macchina x86-64 e potresti usare la convenzione di chiamata x86-64 SysV x32 per tenere conto del conteggio edie del puntatore esi(forse non con estensione zero, quindi forse confondere le cose e richiedere un 64 bit zero-pointer esteso). (x32 quindi puoi tranquillamente usare la matematica del puntatore a 32 bit, ma hai ancora la convenzione di chiamata register-args. Dato che non usi inc, non c'è un aspetto negativo nella modalità lunga.)
Peter Cordes,

Hai preso edxin considerazione l'idea di mantenere l' ordine invertito in byte? bswap edxè solo 2B. shr %edxè 2B, uguale al turno sinistro con add %edx,%edx. Questo probabilmente non è utile; A meno che non consenta una maggiore ottimizzazione, si risparmia 3B per il shl $24, %eax, ma si spendono 4B per xor %eax,%eaxl'inizio e bswap %edxalla fine. L'azzeramento di eax ti consente di usarlo cdqa zero %edx, quindi nel complesso è un lavaggio. Tuttavia, avrebbe prestazioni migliori: evita lo stallo / rallentamento del registro parziale su ogni iterazione dalla scrittura ale dalla lettura eaxcon shl. : P
Peter Cordes,

1
Ti sei confuso con la domanda Adler-32, che ha un limite di lunghezza. Questa domanda non ha un limite di lunghezza esplicita.
Mark Adler,

1
Potrebbe esserci un modo per accorciarlo con l'istruzione PCLMULQDQ. Tuttavia, il suo uso tende a richiedere molte costanti, quindi probabilmente no.
Mark Adler,


4

Rubino, 142 byte

Funzione anonima; accetta una stringa come input, restituisce un numero intero.

->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}

2
Puoi cambiare il tuo nome in modo che le persone possano distinguerci? XD
Leaky Nun

2
@KennyLau devi essere così esigente ... OK bene
Value Ink

Stavo solo scherzando xd
Leaky Nun

4

Gelatina , 23 byte

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

L'input è in forma di un elenco di numeri interi. Provalo online! o verifica tutti i casi di test .

Come funziona

Mentre Jelly ha XOR bit a bit, riempire l'ingresso di zero e allineare il polinomio con la cifra binaria più significativa rende questo approccio, che utilizza invece elenchi di bit, un po 'più breve.

ḅ⁹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.


3

CJam, 37 36 byte

q256b32m<{Yb4374732215Yb.^Yb_Yb32>}g

Provalo qui.

Spiegazione

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

q256bYb_,{(4374732215Ybf*1>.^}*Ybsalva qualche byte.
Dennis,

@Dennis È davvero intelligente, sentiti libero di farne una risposta separata. :)
Martin Ender,

3

Pyth, 28 byte

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

Provalo online: dimostrazione o Test Suite

Spiegazione:

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

2

JavaScript (ES6), 180 byte

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)

La mancanza di un operatore XOR a 33 bit, o anche di un operatore XOR a 32 bit senza segno, non è utile.


1

CJam, 33 byte

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

L'input è in forma di stringa. Provalo online!

Come funziona

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.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.