Calcola il checksum Adler-32


32

sfondo

Adler-32 è un checksum a 32 bit inventato da Mark Adler nel 1995 che fa parte della libreria zlib ampiamente utilizzata (anch'essa sviluppata da Adler). Adler-32 non è affidabile come un controllo di ridondanza ciclica a 32 bit , ma - almeno nel software - è molto più veloce e più facile da implementare.

Definizione

Sia B = [b 1 , ⋯, b n ] un array di byte.

Il checksum Adler-32 di B è definito come il risultato di basso + 65536 × alto , dove:

  • basso: = ((1 + b 1 + ⋯ + b n ) mod 65521)

  • alto: = (((1 + b 1 ) + (1 + b 1 + b 2 ) + ⋯ (1 + b 1 + ⋯ + b n )) mod 65521)

Compito

Dato un array di byte come input, calcola e restituisce il checksum Adler-32, rispettando quanto segue.

  • È possibile accettare l'input come una matrice di byte o numeri interi o come stringa.

    In entrambi i casi, nell'input si verificheranno solo byte corrispondenti a caratteri ASCII stampabili.

    Si può presumere che la lunghezza dell'ingresso soddisfi 0 <lunghezza ≤ 4096 .

  • Se si sceglie di stampare l'output, è possibile utilizzare qualsiasi base positiva fino a 256 inclusi.

    Se si sceglie unario, assicurarsi che l'interprete possa gestire fino a 2 32 - 983056 byte di output su una macchina con 16 GiB di RAM.

  • Gli incorporati che calcolano il checksum Adler-32 sono vietati.

  • Si applicano le regole standard del .

Casi test

String:     "Eagles are great!"
Byte array: [69, 97, 103, 108, 101, 115, 32, 97, 114, 101, 32, 103, 114, 101, 97, 116, 33]
Checksum:   918816254

String:     "Programming Puzzles & Code Golf"
Byte array: [80, 114, 111, 103, 114, 97, 109, 109, 105, 110, 103, 32, 80, 117, 122, 122, 108, 101, 115, 32, 38, 32, 67, 111, 100, 101, 32, 71, 111, 108, 102]
Checksum:   3133147946

String:     "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
Byte array: [126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126]
Checksum:   68095937

String:     <1040 question marks>
Byte array: <1040 copies of 63>
Checksum:   2181038080

7
Noterò che molte delle risposte qui falliranno con sequenze di input grandi o molto grandi quando traboccano delle somme intere a 32 o 64 bit, a causa del differimento dell'operazione del modulo fino a dopo il calcolo delle somme. Un'implementazione veramente conforme dovrebbe eseguire l'operazione modulo almeno periodicamente per evitare che le somme trabocchino. Un numero intero con segno a 32 bit verrebbe traboccato dopo solo 4096 0xff. Un numero intero con segno a 64 bit verrebbe traboccato dopo 256 MiB di 0xff.
Mark Adler,

@MarkAdler Hm, punto giusto. Poiché non ho specificato che le soluzioni avrebbero dovuto funzionare per stringhe arbitrariamente lunghe e non voglio invalidare le risposte esistenti, imposterò un limite per la lunghezza dell'input.
Dennis,

@MarkAdler Non penso che importi. Sono abbastanza certo che l'overflow (numeri interi a 32 bit con segno) può verificarsi solo con 4104 o più byte di input, poiché il valore massimo di high prima del modulo è n * (n + 1) / 2 * 255 + n . Inoltre, la sfida limita l'input ai byte corrispondenti ai caratteri ASCII stampabili.
Dennis,

Potremmo anche consentire alle lingue di overflow dei loro tipi numerici e richiedere solo che il risultato restituito sia equivalente, tenendo conto dell'overflow, per il risultato corretto.
miglia

1
@PeterCordes Sì, le matrici di 32 bit integra perfettamente. Almeno secondo me, i contributi dovrebbero concentrarsi sul golf dell'algoritmo e prestare la minima attenzione possibile all'I / O.
Dennis,

Risposte:


3

Gelatina, 19 17 byte

+\,S‘S€%65521ḅ⁹²¤

Provalo online!

+\,S‘S€%65521ḅ⁹²¤    Main monadic chain. Takes array as only argument.

                     The array is shown here as [b1 b2 ... bn].
+\                   Reduce by addition (+) while returning immediate results.
                         yields [b1 b1+b2 ... b1+b2+...+bn].

  ,                  Concatenate with...
   S                 the sum of the argument.
                         yields [[b1 b1+b2 ... b1+b2+...+bn] b1+b2+...+bn].

    ‘                Increment [each].
                         yields [[1+b1 1+b1+b2 ... 1+b1+b2+...+bn] 1+b1+b2+...+bn].

     S€              Sum each list.
                         yields [[1+b1+1+b1+b2+...+1+b1+b2+...+bn] 1+b1+b2+...+bn].

       %65521        Modulo [each] by 65521.

             ḅ⁹²¤    Convert from base    65536    to integer.
              ⁹                        256
               ²                           squared

Meglio ancora:⁹²¤
Dennis

1
@Dennis Ho superato il tuo 18 byte allora.
Leaky Nun,

1
Bene, hai superato di gran lunga ..
Leaky Nun

64

Mathematica, 46 byte

{1,4^8}.Fold[##+{0,#&@@#}&,{1,0},#]~Mod~65521&

Una funzione anonima che accetta un array intero e restituisce l'Adler-32, con alcuni miglioramenti da miglia e Martin (vedi commenti).

miglia 'è anche 46 byte , ma più veloce:

{1,4^8}.{Tr@#+1,Tr[Accumulate@#+1]}~Mod~65521&

37
... Hai appena giocato a golf il tuo famoso algoritmo?
Mego

25
Perdonami se sono un po 'colpito dalle stelle. Non capita tutti i giorni di vedere un nome così grande nell'ingegneria del software sul nostro modesto sito. Benvenuto a bordo!
Mego

6
Non così grande.
Mark Adler,

3
Se intendi me, questa è la prima volta che ho pensato di implementare Adler-32 in Mathematica.
Mark Adler,

9
O forse hai preparato questa soluzione da quando sei entrato in Code Golf, aspettando solo che ti venga chiesto. "Finalmente!" ;-)
Antti Haapala il

13

Julia, 73 46 byte

x->[sum(x)+1;sum(cumsum(x)+1)]%65521⋅[1;4^8]

Questa è una funzione anonima che accetta un array e restituisce un numero intero. Per chiamarlo, assegnarlo a una variabile.

Combiniamo sum(x) + 1e sum(cumsum(x) + 1)in una matrice, dove si xtrova la matrice di input, e prendiamo ciascun modulo 65521. Quindi calcoliamo il prodotto punto con 1 e 4 8 , che ci dà (sum(x) + 1) + 4^8 * sum(cumsum(x) + 1), che è esattamente la formula Adler-32.

Provalo online! (Include tutti i casi di test)

Risparmiato 27 byte grazie a Sp3000 e Dennis!


Wow, è davvero intelligente.
gatto

@cat Devo ringraziare Sp3000 e Dennis per la maggior parte dell'intelligenza. :)
Alex A.

11

funzione codice macchina x86-64: 33 32 byte (o 31 30 byte con un int[]input anziché char[])

x86-32 funzione codice macchina: 31 byte

Come frammento di codice inline-asm GNU C: salva 2B 1B (solo l' retinsn).

Fonte commentata e driver di test su github

La versione a 64 bit è richiamabile direttamente da C con l'ABI standard System V x86-64 (usando 2 args fittizi per ottenere arg nei reg che voglio). Le convenzioni di chiamata personalizzate non sono insolite per il codice asm, quindi questa è una funzione bonus.

Il codice macchina a 32 bit consente di risparmiare 1B, poiché l'unione delle metà alte e basse push16/push16 => pop32funziona solo in modalità 32 bit. Una funzione a 32 bit avrebbe bisogno di una convenzione di chiamata personalizzata. Non dovremmo tenerlo contro, ma chiamare da C richiede una funzione wrapper.

Dopo l'elaborazione 4096 ~(ASCII 126) byte, high = 0x3f040000, low = 0x7e001. Quindi il highbit più significativo non è ancora impostato. Il mio codice ne approfitta, estendendo il segno eaxin edx:eaxcon cdqun modo di azzeramento edx.

# See the NASM source below
0000000000401120 <golfed_adler32_amd64>:
  401120:       31 c0                   xor    eax,eax
  401122:       99                      cdq    
  401123:       8d 7a 01                lea    edi,[rdx+0x1]
0000000000401126 <golfed_adler32_amd64.byteloop>:
  401126:       ac                      lods   al,BYTE PTR ds:[rsi]
  401127:       01 c7                   add    edi,eax
  401129:       01 fa                   add    edx,edi
  40112b:       e2 f9                   loop   401126 <golfed_adler32_amd64.byteloop>
000000000040112d <golfed_adler32_amd64.end>:
  40112d:       66 b9 f1 ff             mov    cx,0xfff1
  401131:       92                      xchg   edx,eax
  401132:       99                      cdq    
  401133:       f7 f1                   div    ecx
  401135:       52                      push   rdx
  401136:       97                      xchg   edi,eax
  401137:       99                      cdq    
  401138:       f7 f1                   div    ecx
  40113a:       66 52                   push   dx      # this is the diff from last version: evil push/pop instead of shift/add
  40113c:       58                      pop    rax
  40113d:       66 5a                   pop    dx
  40113f:       c3                      ret    
0000000000401140 <golfed_adler32_amd64_end>:

0x40 - 0x20 = 32 byte.


Fonte commentata NASM:

trucchi:

  • xchg eax, r32è un byte; più economico di mov. 8086 necessitavano di dati in ax per molte più cose di> = 386, quindi decisero di dedicare molto spazio all'opcode su quello ora usato raramente xchg ax, r16.

  • Mescolando push64 e push16 per unire alto e basso in un unico registro si risparmiano le istruzioni di spostamento dei dati del reg-reg in circa due divsecondi. La versione a 32 bit di questo trucco funziona ancora meglio: push16 / push16 / pop32è solo 5B in totale, non 6.

Dal momento che spingiamo / pop, questo non è sicuro per l'asline in linea nell'ABI SysV amd64 (con una zona rossa) .

golfed_adler32_amd64_v3:   ; (int dummy, const char *buf, int dummy, uint64_t len)

    ;; args: len in rcx,  const char *buf in rsi
    ;; Without dummy args, (unsigned len, const char *buf),  mov ecx, edi is the obvious solution, costing 2 bytes

    xor     eax,eax         ; scratch reg for loading bytes
    cdq                     ; edx: high=0
    lea     edi, [rdx+1]    ; edi: low=1
    ;jrcxz  .end            ; We don't handle len=0.  unlike rep, loop only checks rcx after decrementing
.byteloop:
    lodsb                   ; upper 24b of eax stays zeroed (no partial-register stall on Intel P6/SnB-family CPUs, thanks to the xor-zeroing)
    add     edi, eax        ; low += zero_extend(buf[i])
    add     edx, edi        ; high += low
    loop   .byteloop
.end:
    ;; exit when ecx = 0, eax = last byte of buf
    ;; lodsb at this point would load the terminating 0 byte, conveniently leaving eax=0

    mov     cx, 65521       ; ecx = m = adler32 magic constant.  (upper 16b of ecx is zero from the loop exit condition.  This saves 1B over mov r32,imm32)
    ;sub    cx, (65536 - 65521) ; the immediate is small enough to use the imm8 encoding.  No saving over mov, though, since this needs a mod/rm byte

    xchg    eax, edx        ; eax = high,  edx = buf[last_byte]
    cdq                     ; could be removed if we could arrange things so the loop ended with a load of the 0 byte

    div     ecx             ; div instead of idiv to fault instead of returning wrong answers if high has overflowed to negative.  (-1234 % m is negative)
    push    rdx             ; push high%m and 6B of zero padding

    xchg    eax, edi        ; eax=low
    cdq
    div     ecx             ; edx = low%m

    ;; concatenate the two 16bit halves of the result by putting them in contiguous memory
    push    dx              ; push low%m with no padding
    pop     rax             ; pop  high%m << 16 | low%m   (x86 is little-endian)

    pop     dx              ; add rsp, 2 to restore the stack pointer

    ;; outside of 16bit code, we can't justify returning the result in the dx:ax register pair
    ret
golfed_adler32_amd64_end_v3:

Ho anche considerato l'utilizzo rcxcome indice di array, invece di avere due contatori di loop, ma adler32 (s)! = Adler32 (reverse (s)). Quindi non abbiamo potuto usare loop. Il conteggio da -len a zero e l'utilizzo movzx r32, [rsi+rcx]usa solo troppi byte.

Se vogliamo considerare di aumentare noi stessi il puntatore, il codice a 32 bit è probabilmente la strada da percorrere. Anche l'ABI x32 (puntatori a 32 bit) non è sufficiente, perché inc esiè 2B su amd64, ma 1B su i386. Sembra difficile da battere xor eax,eax/ lodsb/ loop: 4B totali per ottenere ogni elemento a sua volta esteso a zero in eax. inc esi/ movzx r32, byte [esi]/ loopè 5B.

scasè un'altra opzione per incrementare un puntatore con un'istruzione 1B in modalità 64 bit. ( rdi/ ediinvece di rsi, quindi prenderemmo il puntatore arg rdi). Tuttavia, non possiamo usare il risultato flag scascome condizione di loop, perché non vogliamo mantenere azzerato eax. Un'allocazione di registro diversa potrebbe salvare un byte dopo il ciclo.


int[] ingresso

La piena funzionalità uint8_t[]è la risposta "principale", perché è una sfida più interessante. Disimballare int[]è una cosa irragionevole chiedere al nostro chiamante di fare in questa lingua, ma risparmia 2B.

Se prendiamo il nostro input come un array decompresso di numeri interi a 32 bit, possiamo salvare facilmente un byte (usare lodsde sostituire xor eax,eax / cdqcon just xor edx,edx).

Possiamo salvare un altro byte azzerando edx con lodsd/ cdqe riorganizzando il loop in modo che carichi l'elemento di terminazione 0 prima di uscire. (Stiamo ancora supponendo che esista, anche se questa è una matrice di int, non una stringa).

; untested: I didn't modify the test driver to unpack strings for this
golfed_adler32_int_array:
    ; xor   edx,edx
    lodsd                   ; first element. only the low byte non-zero
    cdq                     ; edx: high=0
    lea     edi, [rdx+1]    ; edi: low=1
    ;jrcxz  .end            ; handle len=0?  unlike rep, loop only checks rcx after decrementing
.intloop:
    add     edi, eax        ; low += buf[i]
    add     edx, edi        ; high += low
    lodsd                   ; load buf[i+1] for next iteration
    loop   .intloop
.end:
    ;; exit when ecx = 0, eax = terminating 0

    xchg    eax, edx
    ;cdq               ; edx=0 already, ready for div
    ; same as the char version

Ho anche realizzato una versione non testata che utilizza scasd(versione 1B di add edi,4) e add eax, [rdi]invece di lodsd, ma è anche 30 byte. I risparmi derivanti dall'avere highin eax alla fine del ciclo sono bilanciati da un codice più grande altrove. Ha il vantaggio di non dipendere da un 0elemento di terminazione nell'input, tuttavia, il che è forse irragionevole per un array non compresso in cui ci viene data esplicitamente anche la lunghezza.


Driver di test C ++ 11

Vedi il link github. Questa risposta stava diventando troppo grande e il driver di test ha ottenuto più funzionalità con un codice più grande.


2
Ho permesso numeri interi anziché byte principalmente perché molte lingue non hanno nemmeno un tipo di byte. I numeri interi a 32 bit possono essere una scelta innaturale per l'assemblaggio, ma il codice golf consiste nello spremere l'ultimo byte rimanendo all'interno delle regole. Se una scelta "innaturale" porta a un conteggio di byte inferiore, direi di provarci.
Dennis,

@Dennis: capisco la necessità della regola per alcune lingue. Vorrei che ci fosse un modo per la regola di lasciarti usare solo int[]se fosse necessario, o di salvare più di 4 byte di codice o qualcosa del genere. Non ho problemi a presentare una soluzione al adler32(int[])problema, ma ritengo che il adler32(char[])problema sia più interessante, dal momento che è la vera funzione adler32. È quello che voglio davvero giocare a golf in asm. (E mi piacerebbe moltissimo salvare un altro byte in qualche modo, dato che nella vita reale, 33 byte = 48 byte se si utilizza la funzione successiva ALIGN 16). Immagino che continuerò a giocare a golf entrambi.
Peter Cordes,

@Dennis: inoltre, dobbiamo gestire il caso len = 0? Salvo 2B usando uno do{}while(--len)stile di loop invece di a while(len--){}.
Peter Cordes,

4
Quando si tratta di spiegazioni, più dettagliate, meglio è.
Dennis,

3
@cat: No, non lo trovo doloroso. Non passerei il tempo a scrivere risposte Stackoverflow a domande asm / performance e ad aggiornare il wiki x86 tag se lo facessi: P Se vuoi sapere perché il codice scorre lento o veloce, devi guardare e capire l'asm. Una volta che lo fai per un po ', inizi a vedere quando il compilatore potrebbe aver reso il codice più veloce ... e alla fine inizi a pensare a come il compilatore potrebbe compilare il codice mentre lo scrivi. L'ottimizzazione per la dimensione del codice anziché per le prestazioni a volte è un cambiamento interessante.
Peter Cordes,

8

MATL , 22 byte

tsQwYsQsh16W15-\l8Mh*s

L'input può essere una matrice di numeri o la stringa ASCII corrispondente.

Provalo online!

Spiegazione

t       % Take array or string as input. Duplicate
sQ      % Sum all its values, and add 1
wYsQs   % Swap. Cumulative sum, add 1, sum
h       % Concatenate horizontally
16W     % 2^16: gives 65536
15-     % Subtract 15: gives 65521
\       % Element-wise modulo operation
l       % Push 1
8M      % Push 65536 again
h       % Concatenate horizontally: gives array [1, 65535]
*s      % Element-wise multiplication and sum. Display

7

In realtà, 36 byte

;Σu@;╗lR`╜HΣu`MΣk`:65521@%`M1#84ⁿ@q*

Provalo online!

Spiegazione:

;Σu@;╗lR`╜HΣu`MΣk`:65521@%`M1#84ⁿ@q*
;Σu                                   sum(input)+1
   @;╗lR                              push a copy of input to reg0, push range(1, len(input)+1)
        `╜HΣu`M                       map over range: sum(head(reg0,n))+1
               Σk                     sum, combine lower and upper into a list
                 `:65521@%`M          modulo each by 65521
                            1#84ⁿ@q*  dot product with [1,4**8]

7

Java, 84 byte

long a(int[]i){long a=1,b=0;for(int p:i)b=(b+(a=(a+p)%(p=65521)))%p;return b<<16|a;}

Se si suppone che le soluzioni Java siano sempre codice compilabile completo, faccelo sapere.

Ungolfed

long a(int[] i) {
    long a = 1, b = 0;
    for (int p : i) b = (b + (a = (a + p) % (p = 65521))) % p;
    return b << 16 | a;
}

Nota

Dovrai convertire l'ingresso Stringin int[]( int[]è un byte più corto di byte[]o char[]).

Produzione

String:     "Eagles are great!"
Byte Array: [69, 97, 103, 108, 101, 115, 32, 97, 114, 101, 32, 103, 114, 101, 97, 116, 33]
Checksum:   918816254
Expected:   918816254

String:     "Programming Puzzles & Code Golf"
Byte Array: [80, 114, 111, 103, 114, 97, 109, 109, 105, 110, 103, 32, 80, 117, 122, 122, 108, 101, 115, 32, 38, 32, 67, 111, 100, 101, 32, 71, 111, 108, 102]
Checksum:   3133147946
Expected:   3133147946

String:     "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
Byte Array: [126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126]
Checksum:   68095937
Expected:   68095937

String:     "?????????...?"
Byte Array: [63, 63, 63, 63, 63, 63, 63, 63, 63, ...,63]
Checksum:   2181038080
Expected:   2181038080

1
Bella risposta, e benvenuta nel sito! Inoltre, le soluzioni che non sono complete e compilabili vanno bene a meno che la sfida non dichiari esplicitamente che dovrebbe essere un programma completo. Questa è una funzione completa, quindi conta.
DJMcMayhem

6

Piet, 120 codici codelsize 1

Con dimensione del codice 20:

dimensione in codice 20

Note / Come funziona?

  • Poiché non è possibile utilizzare un array o una stringa come input, questo programma funziona prendendo come input una serie di numeri interi (che rappresentano caratteri ASCII). All'inizio ho pensato di usare input di caratteri ma ho faticato a trovare una buona soluzione per la terminazione, quindi ora termina quando viene inserito un numero inferiore a 1. Inizialmente erano solo valori negativi per la terminazione, ma ho dovuto modificare l'inizializzazione dopo aver scritto il programma, quindi ora non riesco ad adattare il necessario 2, solo un 1(26/45 sull'immagine di traccia). Questo non importa però perché, secondo le regole della sfida, sono ammessi solo caratteri ASCII stampabili.

  • Ho lottato a lungo con il rientro del loop, anche se alla fine ho trovato la soluzione abbastanza elegante. No pointero switchoperazioni, solo l'interprete corre contro i muri fino a quando non ritorna nel codice verde per leggere l'input (43-> 44 sulle immagini della traccia).

  • La terminazione del loop viene ottenuta duplicando prima l'input, aggiungendo 1 e quindi controllando se è maggiore di 1. In caso affermativo, il selettore di codici viene attivato e l'esecuzione continua sul percorso inferiore. In caso contrario, il programma continua a sinistra (codici giallo brillante, 31/50 sulle immagini di traccia).

  • La dimensione di input supportata dipende dall'implementazione dell'interprete, anche se sarebbe possibile supportare un input arbitrariamente grande con l'interprete giusto (ad esempio, un interprete Java che utilizza BigIntegercome valori interni)

  • Ho appena visto che l'installazione include uno non necessario DUPe CC(7-> 8-> 9 nelle immagini di traccia). Non ho idea di come sia successo. Questo è effettivamente un noop però, attiva e disattiva il selettore di codici 16 volte, senza risultati.

Immagini di traccia Npiet

Setup e primo loop:

StartTrace

Terminazione, uscita ed uscita del loop:

endtrace

Uscite

Perdonami se includo solo un output, ci vuole solo molto tempo per inserire: ^)

String: "Eagles are great!"

PS B:\Marvin\Desktop\Piet> .\npiet.exe adler32.png
? 69
? 97
? 103
? 108
? 101
? 115
? 32
? 97
? 114
? 101
? 32
? 103
? 114
? 101
? 97
? 116
? 33
? -1
918816254

Traccia Npiet per [65, -1]

trace: step 0  (0,0/r,l nR -> 1,0/r,l dR):
action: push, value 4
trace: stack (1 values): 4

trace: step 1  (1,0/r,l dR -> 2,0/r,l dB):
action: duplicate
trace: stack (2 values): 4 4

trace: step 2  (2,0/r,l dB -> 3,0/r,l nM):
action: multiply
trace: stack (1 values): 16

trace: step 3  (3,0/r,l nM -> 4,0/r,l nC):
action: duplicate
trace: stack (2 values): 16 16

trace: step 4  (4,0/r,l nC -> 5,0/r,l nY):
action: duplicate
trace: stack (3 values): 16 16 16

trace: step 5  (5,0/r,l nY -> 6,0/r,l nM):
action: duplicate
trace: stack (4 values): 16 16 16 16

trace: step 6  (6,0/r,l nM -> 7,0/r,l nC):
action: duplicate
trace: stack (5 values): 16 16 16 16 16

trace: step 7  (7,0/r,l nC -> 8,0/r,l nY):
action: duplicate
trace: stack (6 values): 16 16 16 16 16 16

trace: step 8  (8,0/r,l nY -> 9,0/r,l lB):
action: switch
trace: stack (5 values): 16 16 16 16 16
trace: stack (5 values): 16 16 16 16 16

trace: step 9  (9,0/r,l lB -> 10,0/r,l dM):
action: multiply
trace: stack (4 values): 256 16 16 16

trace: step 10  (10,0/r,l dM -> 11,0/r,l nR):
action: multiply
trace: stack (3 values): 4096 16 16

trace: step 11  (11,0/r,l nR -> 12,0/r,l lY):
action: multiply
trace: stack (2 values): 65536 16

trace: step 12  (12,0/r,l lY -> 13,0/r,l lM):
action: duplicate
trace: stack (3 values): 65536 65536 16

trace: step 13  (13,0/r,l lM -> 14,0/r,l nM):
action: push, value 3
trace: stack (4 values): 3 65536 65536 16

trace: step 14  (14,0/r,l nM -> 15,0/r,l dM):
action: push, value 2
trace: stack (5 values): 2 3 65536 65536 16

trace: step 15  (15,0/r,l dM -> 16,0/r,l lC):
action: roll
trace: stack (3 values): 16 65536 65536

trace: step 16  (16,0/r,l lC -> 17,0/r,l nB):
action: sub
trace: stack (2 values): 65520 65536

trace: step 17  (17,0/r,l nB -> 18,0/r,l dB):
action: push, value 1
trace: stack (3 values): 1 65520 65536

trace: step 18  (18,0/r,l dB -> 19,0/r,l dM):
action: add
trace: stack (2 values): 65521 65536

trace: step 19  (19,0/r,l dM -> 19,1/d,r dC):
action: duplicate
trace: stack (3 values): 65521 65521 65536

trace: step 20  (19,1/d,r dC -> 18,1/l,l lC):
action: push, value 1
trace: stack (4 values): 1 65521 65521 65536

trace: step 21  (18,1/l,l lC -> 17,1/l,l nC):
action: push, value 1
trace: stack (5 values): 1 1 65521 65521 65536

trace: step 22  (17,1/l,l nC -> 16,1/l,l dB):
action: sub
trace: stack (4 values): 0 65521 65521 65536

trace: step 23  (16,1/l,l dB -> 15,1/l,l lB):
action: push, value 1
trace: stack (5 values): 1 0 65521 65521 65536

trace: step 24  (15,1/l,l lB -> 13,2/l,l dG):
action: in(number)
? 65
trace: stack (6 values): 65 1 0 65521 65521 65536

trace: step 25  (13,2/l,l dG -> 12,2/l,l dR):
action: duplicate
trace: stack (7 values): 65 65 1 0 65521 65521 65536

trace: step 26  (12,2/l,l dR -> 11,2/l,l lR):
action: push, value 1
trace: stack (8 values): 1 65 65 1 0 65521 65521 65536

trace: step 27  (11,2/l,l lR -> 10,2/l,l lY):
action: add
trace: stack (7 values): 66 65 1 0 65521 65521 65536

trace: step 28  (10,2/l,l lY -> 9,2/l,l nY):
action: push, value 1
trace: stack (8 values): 1 66 65 1 0 65521 65521 65536

trace: step 29  (9,2/l,l nY -> 8,1/l,r nB):
action: greater
trace: stack (7 values): 1 65 1 0 65521 65521 65536

trace: step 30  (8,1/l,r nB -> 7,1/l,r lY):
action: switch
trace: stack (6 values): 65 1 0 65521 65521 65536
trace: stack (6 values): 65 1 0 65521 65521 65536

trace: step 31  (7,1/l,l lY -> 6,2/l,l nY):
action: push, value 2
trace: stack (7 values): 2 65 1 0 65521 65521 65536

trace: step 32  (6,2/l,l nY -> 5,3/l,l dB):
action: pointer
trace: stack (6 values): 65 1 0 65521 65521 65536

trace: step 33  (5,3/r,l dB -> 7,4/r,l dM):
action: add
trace: stack (5 values): 66 0 65521 65521 65536

trace: step 34  (7,4/r,l dM -> 8,4/r,l dC):
action: duplicate
trace: stack (6 values): 66 66 0 65521 65521 65536

trace: step 35  (8,4/r,l dC -> 9,3/r,l lC):
action: push, value 3
trace: stack (7 values): 3 66 66 0 65521 65521 65536

trace: step 36  (9,3/r,l lC -> 10,3/r,l nC):
action: push, value 2
trace: stack (8 values): 2 3 66 66 0 65521 65521 65536

trace: step 37  (10,3/r,l nC -> 11,3/r,l dY):
action: roll
trace: stack (6 values): 0 66 66 65521 65521 65536

trace: step 38  (11,3/r,l dY -> 12,3/r,l dG):
action: add
trace: stack (5 values): 66 66 65521 65521 65536

trace: step 39  (12,3/r,l dG -> 13,3/r,l lG):
action: push, value 2
trace: stack (6 values): 2 66 66 65521 65521 65536

trace: step 40  (13,3/r,l lG -> 14,3/r,l nG):
action: push, value 1
trace: stack (7 values): 1 2 66 66 65521 65521 65536

trace: step 41  (14,3/r,l nG -> 15,3/r,l dR):
action: roll
trace: stack (5 values): 66 66 65521 65521 65536
trace: white cell(s) crossed - continuing with no command at 17,3...

trace: step 42  (15,3/r,l dR -> 17,3/r,l lB):

trace: step 43  (17,3/r,l lB -> 13,2/l,l dG):
action: in(number)
? -1
trace: stack (6 values): -1 66 66 65521 65521 65536

trace: step 44  (13,2/l,l dG -> 12,2/l,l dR):
action: duplicate
trace: stack (7 values): -1 -1 66 66 65521 65521 65536

trace: step 45  (12,2/l,l dR -> 11,2/l,l lR):
action: push, value 1
trace: stack (8 values): 1 -1 -1 66 66 65521 65521 65536

trace: step 46  (11,2/l,l lR -> 10,2/l,l lY):
action: add
trace: stack (7 values): 0 -1 66 66 65521 65521 65536

trace: step 47  (10,2/l,l lY -> 9,2/l,l nY):
action: push, value 1
trace: stack (8 values): 1 0 -1 66 66 65521 65521 65536

trace: step 48  (9,2/l,l nY -> 8,1/l,r nB):
action: greater
trace: stack (7 values): 0 -1 66 66 65521 65521 65536

trace: step 49  (8,1/l,r nB -> 7,1/l,r lY):
action: switch
trace: stack (6 values): -1 66 66 65521 65521 65536
trace: stack (6 values): -1 66 66 65521 65521 65536

trace: step 50  (7,1/l,r lY -> 6,1/l,r dY):
action: pop
trace: stack (5 values): 66 66 65521 65521 65536

trace: step 51  (6,1/l,r dY -> 4,1/l,r lY):
action: push, value 3
trace: stack (6 values): 3 66 66 65521 65521 65536

trace: step 52  (4,1/l,r lY -> 3,1/l,r nY):
action: push, value 2
trace: stack (7 values): 2 3 66 66 65521 65521 65536

trace: step 53  (3,1/l,r nY -> 2,1/l,r nM):
action: duplicate
trace: stack (8 values): 2 2 3 66 66 65521 65521 65536

trace: step 54  (2,1/l,r nM -> 1,1/l,r dG):
action: pointer
trace: stack (7 values): 2 3 66 66 65521 65521 65536

trace: step 55  (1,1/r,r dG -> 2,2/r,r lR):
action: roll
trace: stack (5 values): 65521 66 66 65521 65536

trace: step 56  (2,2/r,r lR -> 2,3/d,l nR):
action: push, value 1
trace: stack (6 values): 1 65521 66 66 65521 65536

trace: step 57  (2,3/d,l nR -> 2,4/d,l lC):
action: switch
trace: stack (5 values): 65521 66 66 65521 65536
trace: stack (5 values): 65521 66 66 65521 65536

trace: step 58  (2,4/d,r lC -> 2,5/d,r nM):
action: mod
trace: stack (4 values): 66 66 65521 65536

trace: step 59  (2,5/d,r nM -> 4,5/r,r dM):
action: push, value 3
trace: stack (5 values): 3 66 66 65521 65536

trace: step 60  (4,5/r,r dM -> 6,5/r,r lM):
action: push, value 2
trace: stack (6 values): 2 3 66 66 65521 65536

trace: step 61  (6,5/r,r lM -> 7,5/r,r nC):
action: roll
trace: stack (4 values): 65521 66 66 65536

trace: step 62  (7,5/r,r nC -> 8,5/r,r dM):
action: mod
trace: stack (3 values): 66 66 65536

trace: step 63  (8,5/r,r dM -> 11,5/r,r lM):
action: push, value 3
trace: stack (4 values): 3 66 66 65536

trace: step 64  (11,5/r,r lM -> 12,5/r,r nM):
action: push, value 1
trace: stack (5 values): 1 3 66 66 65536

trace: step 65  (12,5/r,r nM -> 13,5/r,r dC):
action: roll
trace: stack (3 values): 66 65536 66

trace: step 66  (13,5/r,r dC -> 14,5/r,r nB):
action: multiply
trace: stack (2 values): 4325376 66

trace: step 67  (14,5/r,r nB -> 15,5/r,r nM):
action: add
trace: stack (1 values): 4325442

trace: step 68  (15,5/r,r nM -> 16,5/r,r dB):
action: out(number)
4325442
trace: stack is empty
trace: white cell(s) crossed - continuing with no command at 19,5...

trace: step 69  (16,5/r,r dB -> 19,5/r,r nM):

5

C89, 70 byte

h,l,m=65521;A(char*B){h=0;l=1;while(*B)h+=l+=*B++;return h%m<<16|l%m;}

Per testare (compilare con gcc -std=c89 -lm golf.c):

#include <stdio.h>
int main(int argc, char** argv) {
    printf("%u\n", A("Eagles are great!"));
    printf("%u\n", A("Programming Puzzles & Code Golf"));
    printf("%u\n", A("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"));
    return 0;
}

È così che zlibappare la fonte? Hm ...
cat

1
Questa implementazione ha reso un buon punto di partenza per la mia versione x86 asm.
Peter Cordes,

Può salvare 1 byte usando forinvece di while:for(h=0,l=1;*B;)h+=l+=*B++;
ninjalj

5

Labyrinth , 37 36 32 31 byte

}?"{655:}21:}%=}){%{{36*+!
:++)

Provalo online!

Inserire come un elenco di numeri interi. Il programma termina con un errore (il cui messaggio di errore passa a STDERR).

Spiegazione

Primer labirinto:

  • Labyrinth ha due pile di numeri interi di precisione arbitraria, main e aux (iliary), che inizialmente sono riempiti con una quantità (implicita) infinita di zeri.
  • Il codice sorgente assomiglia a un labirinto, in cui il puntatore dell'istruzione (IP) segue i corridoi quando può (anche dietro gli angoli). Il codice inizia dal primo carattere valido nell'ordine di lettura, ovvero nell'angolo in alto a sinistra in questo caso. Quando l'IP arriva a qualsiasi forma di giunzione (cioè diverse celle adiacenti oltre a quella da cui proviene), sceglierà una direzione basata sulla parte superiore dello stack principale. Le regole di base sono: girare a sinistra quando è negativo, andare avanti quando è zero, girare a destra quando è positivo. E quando uno di questi non è possibile perché c'è un muro, l'IP prenderà la direzione opposta. L'IP si gira anche quando colpisce i vicoli ciechi.
  • Le cifre vengono elaborate moltiplicando la parte superiore dello stack principale per 10 e quindi aggiungendo la cifra. Per iniziare un nuovo numero, puoi spingere uno zero con _.

Sebbene il codice inizi con una "stanza" 4x2, in realtà si tratta di due loop separati, due per due, uniti insieme. L'IP semplicemente si attacca a un loop alla volta a causa dei valori dello stack.

Quindi il codice inizia con un ciclo 2x2 (in senso orario) che legge l'input mentre calcola le somme del prefisso:

}   Move last prefix sum over to aux.
?   Read an integer from STDIN or push 0 on EOF, which exits the loop.
+   Add current value to prefix sum.
:   Duplicate this prefix sum.

Ora abbiamo tutte le somme del prefisso nello stack aux , così come una copia della somma su tutti i valori e 0da EOF su main . Con ciò, entriamo in un altro ciclo 2x2 (in senso orario) che somma tutte le somme del prefisso da calcolare HIGH.

"   No-op. Does nothing.
{   Pull one prefix sum over from aux. When we're done, this fetches a 0,
    which exits the loop.
)   Increment prefix sum.
+   Add it to HIGH.

Lo stack principale ora ha LOW - 1e HIGHe zero, tranne che non abbiamo ancora preso il modulo. Il resto del codice è completamente lineare:

655      Turn the zero into 655.
:}       Make a copy and shift it over to aux.
21       Turn the copy on main into 65521.
:}       Make a copy and shift it over to aux.
%        Take HIGH mod 65521.
=        Swap HIGH with the other copy of 65521 on aux.
}){      Move 65521 back to aux, increment LOW-1 to LOW, 
         move 65521 back to main.
%        Take LOW mod 65521.
{        Move HIGH back to main.
{        Move the other copy of 655 back to main.
36       Turn it into 65536.
*        Multiply HIGH by that.
+        Add it to LOW.
!        Print it.

L'IP ora raggiunge un vicolo cieco e si gira. Gli +e *sono essenzialmente non operativi, a causa degli zeri nella parte inferiore dello stack. L' 36ora trasforma la cima del main in 63, ma i due {{estraggono due zeri da aux sopra di esso. Quindi %tenta di dividere per zero che termina il programma.

Si noti che Labyrinth utilizza numeri interi di precisione arbitraria, quindi il rinvio del modulo fino alla fine della somma non causerà problemi con l'overflow dei numeri interi.


5

Python 2, 60 58 byte

H=h=65521
l=1
for n in input():l+=n;h+=l
print h%H<<16|l%H

Un approccio piuttosto semplice. Questo è un programma completo che accetta un elenco di numeri interi tramite STDIN, ad es [72, 105, 33].

(Grazie a @xnor per il fantastico suggerimento di aliasing / inizializzazione)


2
Puoi fare H=h=65521l'inizializzazione hmentre aliasing 65521.
xnor

4

J, 30 byte

+/(+65536&*)&(65521|+/)&:>:+/\

Questo potrebbe probabilmente essere condensato di più con un treno diverso.

uso

Qui x $ ycrea un elenco con xcopie di y.

   f =: +/(+65536&*)&(65521|+/)&:>:+/\
   f 69 97 103 108 101 115 32 97 114 101 32 103 114 101 97 116 33
918816254
   f 80 114 111 103 114 97 109 109 105 110 103 32 80 117 122 122 108 101 115 32 38 32 67 111 100 101 32 71 111 108 102
3133147946
   f (32 $ 126)
68095937
   f (1040 $ 63)
2181038080
   f (4096 $ 255)
2170679522

Spiegazione

+/(+65536&*)&(65521|+/)&:>:+/\
f (           g           ) h     Monad train (f g h) y = (f y) g (h y)
+/                                Sum the input list
                           +/\    Sum each prefix of the input, forms a list
x     f   &   g   &:   h    y     Composed verbs, makes (g (h x)) f (g (h y))
                         >:       Increment the sum and increment each prefix sum
               (m f g) y          Hook, makes m f (g y)
                    +/            Sum the prefix sums
              65521|              Take the sum and prefix total mod 65521
    (f g) y                       Hook again
    65536&*                       Multiply the prefix total by 65536
                                  This is a bonded verb, it will only multiply
                                  using a fixed value now
   +                              Add the sum and scaled prefix total

4

Ottava, 52 50 byte

Salvato 2 byte grazie a @LuisMendo

@(B)mod([sum(S=cumsum(B)+1),S(end)],65521)*[4^8;1]

Accetta una matrice di numeri interi come input.

il minimo viene preso dall'ultimo elemento di alto (prima della somma) anziché calcolare esplicitamente la somma, risparmiando un totale complessivo di ... 1 byte !

Esempio eseguito su ideone .


@LuisMendo Ooh, mi sono dimenticato +B. Immagino che le specifiche di input dicano che puoi prendere numeri interi, quindi forse lo farò.
Becher

3

CJam, 30 29 byte

q~{1$+}*]:)_W>]1fb65521f%2G#b

Inserire come un elenco di numeri interi.

Provalo qui.

Spiegazione

q~       e# Read and evaluate input.
{        e# Fold this block over the list, computing prefix sums.
  1$+    e#   Copy the last prefix and add the current element.
}*
]        e# Wrap the prefix sums in an array.
:)       e# Increment each. This will sum to HIGH.
_W>      e# Copy the list and truncate to only the last element, i.e.
         e# the sum of the entire input plus 1. This is LOW.
]        e# Wrap both of those lists in an array.
1fb      e# Sum each, by treating it as base 1 digits.
65521f%  e# Take each modulo 65521.
2G#b     e# Treat the list as base 65536 digits, computing 65536*HIGH + LOW.

3

Perl 6 , 60 byte

{(.sum+1)%65521+65536*((sum(1,*+.shift...->{!$_})-1)%65521)}

Spiegazione:

{
  # $_ is the implicit parameter for this lambda because this block doesn't have
  # an explicit parameter, and @_ isn't seen inside of it.
  # ( @_ takes precedence over $_ when it is seen by the compiler )

  # .sum is short for $_.sum
  ( .sum + 1 ) % 65521 + 65536
  *
  (
    (
      sum(

        # generate a sequence:

        1,         # starting with 1
        * + .shift # lambda that adds previous result (*) with $_.shift
        ...        # generate until:
        -> { !$_ } # $_ is empty

        # ^ I used a pointy block with zero parameters
        # so that the block doesn't have an implicit parameter
        # like the surrounding block

        # this is so that $_ refers to the outer $_

      ) - 1        # remove starting value
    ) % 65521
  )
}

Test:

#! /usr/bin/env perl6
use v6.c;
use Test;

# give the lambda a name
my &Adler32 = {(.sum+1)%65521+65536*((sum(1,*+.shift...->{!$_})-1)%65521)}

my @tests = (
  (  918816254,  'Eagles are great!'),
  ( 3133147946,  'Programming Puzzles & Code Golf'),
  (   68095937,  '~' x 32,     "'~' x 32"),
  ( 2181038080,  63 xx 1040,   "'?' x 1040"),
);

plan +@tests;

for @tests -> ($checksum, $input, $gist? ) {
  my @array := do given $input {
    when Str { .encode.Array }
    default { .Array }
  }

  is Adler32(@array), $checksum, $gist // $input.perl
}
1..4
ok 1 - "Eagles are great!"
ok 2 - "Programming Puzzles \& Code Golf"
ok 3 - '~' x 32
ok 4 - '?' x 1040

3

Python 3 (79 byte)

Basato sulla soluzione di R. Kap.

lambda w,E=65521:(1+sum(w))%E+(sum(1+sum(w[:i+1])for i in range(len(w)))%E<<16)

Ho sostituito la moltiplicazione con uno spostamento e rimosso una coppia di parentesi.

Poiché non riesco a pubblicare commenti, ho fatto una nuova risposta.


3

Schema, 195 byte

(define(a b)(+(let L((b b)(s 1))(if(=(length b)0)s(L(cdr b)(modulo(+ s(car b))65521))))(* 65536(let H((b b)(s 1)(t 0))(if(=(length b)0)t(let((S(+ s(car b))))(H(cdr b)S(modulo(+ t S)65521))))))))

Se non fosse per tutte quelle parentesi ...


3

Haskell, 54 50 byte

m=(`mod`65521).sum
g x=m(-1:scanl(+)1x)*4^8+m(1:x)

Esempio di utilizzo: g [69,97,103,108,101,115,32,97,114,101,32,103,114,101,97,116,33]-> 918816254.

scanlinclude il valore iniziale (-> 1) nell'elenco (-> [1,1+b1,1+b1+b2,..]), quindi sumè disattivato da 1, che viene risolto anteponendo -1l'elenco prima del riepilogo.

Modifica: Grazie @xnor per 4 byte.


Sembra che è possibile estrarre la somma in m: m=(`mod`65521).sum g x=m(-1:scanl(+)1x)*4^8+m(1:x). Probabilmente c'è un modo migliore per fissare le somme che anteporre.
xnor

3

JavaScript (ES7), 52 50 byte

a=>a.map(b=>h+=l+=b,h=0,l=1)&&l%65521+h%65521*4**8

ES6 richiede 51 byte (sostituire 4 ** 8 con 65536). Se si desidera una versione di stringa, quindi per 69 byte:

s=>[...s].map(c=>h+=l+=c.charCodeAt(),h=0,l=1)&&l%65521+h%65521*65536

Modifica: salvato 2 byte grazie a @ user81655.


3

Funzione ARM Thumb-2 che accetta uint8_t[]: 40 byte (36B per ABI non standard e int[])

Caratteristiche: modulo non differito, quindi gli input di dimensioni arbitrarie vanno bene. In realtà non utilizza l'istruzione di divisione, quindi non è lento. (err, almeno non per quel motivo: P)

Risparmi derivanti dalle seguenti regole meno rigide:

  • -2B se non è necessario salvare i registri prima di utilizzarli.
  • -2B per richiedere al chiamante di decomprimere i byte in un uint32_t[]array.

Quindi, nel migliore dei casi è 36B.

// uint8_t *buf in r0,  uint32_t len in r1
00000000 <adler32arm_golf2>:
   0:   b570            push    {r4, r5, r6, lr} //
   2:   2201            movs    r2, #1          // low
   4:   2300            movs    r3, #0          // high
   6:   f64f 75f1       movw    r5, #65521      ; 0xfff1 = m
0000000a <adler32arm_golf2.byteloop>:
   a:   f810 4b01       ldrb.w  r4, [r0], #1    // post-increment byte-load
   e:   4422            add     r2, r4          // low += *B
  10:   4413            add     r3, r2          // high += low
  12:   42aa            cmp     r2, r5          // subtract if needed instead of deferred modulo
  14:   bf28            it      cs
  16:   1b52            subcs   r2, r2, r5
  18:   42ab            cmp     r3, r5
  1a:   bf28            it      cs              // Predication in thumb mode is still possible, but takes a separate instruction
  1c:   1b5b            subcs   r3, r3, r5
  1e:   3901            subs    r1, #1          // while(--len)
  20:   d1f3            bne.n   a <.byteloop2>
  22:   eac2 4003       pkhbt   r0, r2, r3, lsl #16   // other options are the same size: ORR or ADD.
  26:   bd70            pop     {r4, r5, r6, pc}  // ARM can return by popping the return address (from lr) into the pc; nifty
00000028 <adler32arm_end_golf2>:

0x28 = 40 byte


Gli appunti:

Invece che log%malla fine, lo facciamo if(low>=m) low-=mall'interno del ciclo. Se facciamo il minimo prima del massimo, sappiamo che nessuno dei due può eccedere 2*m, quindi modulo è solo una questione di sottrazione o meno. A cmpe predicato subè solo 6B in modalità Thumb2. Il linguaggio standard per% è 8B in modalità Thumb2:

UDIV R2, R0, R1         // R2 <- R0 / R1
MLS  R0, R1, R2, R0     // R0 <- R0 - (R1 * R2 )

La adler(char *)versione a lunghezza implicita ha le stesse dimensioni del codice della lunghezza esplicita adler(uint8_t[], uint32_t len). Siamo in grado di impostare flag per la condizione di uscita dell'anello con una singola istruzione 2B in entrambi i modi.

La versione a lunghezza implicita ha il vantaggio di funzionare correttamente con la stringa vuota, invece di provare a eseguire il ciclo 2 ^ 32 volte.


assemblare / compilare con:

arm-linux-gnueabi-as --gen-debug -mimplicit-it=always -mfloat-abi=soft -mthumb adler32-arm.S

o

arm-linux-gnueabi-g++ -Wa,-mimplicit-it=always -g -static -std=gnu++14 -Wall -Wextra -Os -march=armv6t2 -mthumb -mfloat-abi=soft test-adler32.cpp -fverbose-asm adler32-arm.S -o test-adler32
qemu-arm ./test-adler32

Senza -static, il processo in esecuzione sotto qemu-armnon ha trovato il suo linker dinamico. (E sì, posso installare un ARM configurazione cross-devel solo per questa risposta, perché ho pensato che la mia idea predicata-Sottrai era pulito.) Su AMD64 di Ubuntu, installare gcc-arm-linux-gnueabi, g++-arm-linux-gnueabi. Ho trovato una gdb-arm-none-eabispecie di connessione a malapena funzionante qemu-arm -g port.

Fonte commentata:

// There's no directive to enable implicit-it=always

// gcc uses compiler uses these in its output
.syntax unified
.arch armv8-a
.fpu softvfp

.thumb      @ aka .code 16

.p2align 4
.globl adler32arm_golf    @ put this label on the one we want to test

.thumb_func
adler32arm_golf:
adler32arm_golf2:   @ (uint8_t buf[], uint32_t len)
        @ r0 = buf
        @ r1 = len
        push    {r4, r5, r6, lr}   @ even number of regs keeps the stack aligned.  Good style? since there's no code-size saving

        movs    r2, #1          @ r2: low
        movs    r3, #0          @ r3: high
                                @ r4 = tmp for loading bytes
        movw    r5, #65521      @ r5: modulo constant

adler32arm_golf2.byteloop2:
        ldrb    r4, [r0], #1    @ *(buf++) post-increment addressing.  4B encoding
        @ldrb    r4, [r0, r1]   @ 2B encoding, but unless we make the caller pass us buf+len and -len, it needs extra code somewhere else
        @ldmia   r0!, {r4}      @ int[] version:  r4 = [r0]; r0+=4;  post-increment addressing.  2B encoding.

        add     r2, r2, r4      @ low += tmp
        add     r3, r3, r2      @ high += low;   // I think it's safe to do this before the modulo range-reduction for low, but it would certainly work to put it after.

        cmp     r2, r5
        subhs   r2, r5          @ if(low>=m) low-=m;   @ 6B total for %.  predicated insns require an IT instruction in thumb2

        cmp     r3, r5
        subhs   r3, r5          @ if(high>=m) high-=m;  // equivalent to high %= m.

        @sub    r1, #1          @ 4B encoding: sub.w to not set flags with immediate
        subs    r1, #1          @ len-- and set flags.  2B encoding
        @cmp    r4, #0          @ null-termination check. 2B encoding
        bne     adler32arm_golf2.byteloop2

@        udiv    r0, r2, r5            @ normal way to do one of the modulos
@        mls     r2, r5, r0, r2         @ r2 = low % m.  8B total for %

        PKHBT   r0, r2, r3, lsl #16     @ 4B   r0 = [ high%m <<16  |   low%m  ]
        @orr     r0, r0, r4, lsl #16    @ 4B
        @orr     r0, r0, r4             @ 4B
        @add     r0, r2, r3, lsl #16    @ 4B
        @add     r0, r0, r4             @ 2B
        pop     {r4, r5, r6, pc}        @ ARM can return by popping the return address (saved from lr) into pc.  Nifty
adler32arm_end_golf2:

test-adler32.cppha gli stessi casi di test e main()la mia risposta x86-64, ma inizia in questo modo:

#include <stdint.h>
uint32_t adler32_simple(const uint8_t *B) {
  const uint32_t m=65521;

  uint32_t h=0, l=1;
  do {
    l += *B++;        // Borrowed from orlp's answer, as a simple reference implementation
    h += l;
    l %= m; h %= m;   // with non-deferred modulo if this is uncommented
  } while(*B);

  return h%m<<16|l%m;
}


#include <stdio.h>
//#include <zlib.h>
#include <string.h>
#include <assert.h>
#include <string>   // useful for the memset-style constructors that repeat a character n times


extern "C" {
    unsigned golfed_adler32_amd64(int /*dummy1*/, const char *buf, int /*dummy2*/, unsigned len);
    unsigned adler32arm_golf(const char *buf, unsigned len);
}
#ifdef __amd64__
#define golfed_adler32(buf, len)   golfed_adler32_amd64(1234, buf, 1234, len)
#elif  __arm__
#define golfed_adler32(buf, len)   adler32arm_golf(buf, len)
#else
#error "no architecture"
#endif

static void test_adler(const char *str)
{
    unsigned len = strlen(str);
//    unsigned zlib = zlib_adler(len, str);
    unsigned reference = adler32_simple((const uint8_t*)str);
    unsigned golfed = golfed_adler32(str, len);

    printf("%s: c:%u asm:%u\n", str, reference, golfed);
    assert(reference == golfed);
}

// main() to call test_adler() unchanged from my amd64 answer, except that the comments about length limits don't apply

3

x86 Funzione codice macchina a 16 bit: 32 byte utilizzando una convenzione di chiamata personalizzata

Args nei registri e non preservare regs diversi da bp (e sp).

Nel codice a 16 bit, restituiamo un valore a 32 bit nella dx:axcoppia di registri. Questo significa che non c'è bisogno di spendere tutte le istruzioni la fusione highe lowin eax. (Ciò consentirebbe di risparmiare byte anche nel codice a 32 e 64 bit, ma possiamo solo giustificare il trasferimento di questo lavoro al chiamante in codice a 16 bit.)

Fonte commentata e driver di test su github (per x86 16, 32 e 64 bit e ARM).

### const char *buf in SI,  uint16_t len in CX
## returns in dx:ax
## also clobbers bx and di.
00000100 <adler32_x16_v6>:
 100:   31 c0                   xor    ax,ax         # set up for lods
 102:   99                      cwd                  # dx= high=0
 103:   bf 01 00                mov    di,0x1        # di= low=0
 106:   bb f1 ff                mov    bx,0xfff1     # bx= m
00000109 <adler32_x16_v6.byteloop>:
 109:   ac                      lods
 10a:   01 c7                   add    di,ax         # low+=buf[i]. modulo-reduce on carry, or on low>=m
 10c:   72 04                   jc     112 <adler32_x16_v6.carry_low>
 10e:   39 df                   cmp    di,bx
 110:   72 02                   jb     114 <adler32_x16_v6.low_mod_m_done>
00000112 <adler32_x16_v6.carry_low>:
 112:   29 df                   sub    di,bx
00000114 <adler32_x16_v6.low_mod_m_done>:
 114:   01 fa                   add    dx,di         # high+=low
 116:   0f 92 d0                setb   al            # store the carry to set up a 32bit dividend.
 119:   92                      xchg   dx,ax
 11a:   f7 f3                   div    bx            # high (including carry) %= m, in dx.  ax=0 or 1 (so we're set for lods next iteration)                                                         
 11c:   e2 eb                   loop   109 <adler32_x16_v6.byteloop>
 11e:   97                      xchg   di,ax         # 
 11f:   c3                      ret    
00000120 <adler32_x16_v6_end>:

0x120 - 0x100 = 32 byte

Testato assemblando lo stesso codice per la modalità a 32 bit, quindi posso chiamarlo (con una funzione wrapper) da C compilato -m32. Per me, la modalità a 16 bit è alquanto interessante, le chiamate di sistema DOS non lo sono. Tutte le istruzioni hanno operandi espliciti, tranne loope lodsb, quindi l'assemblaggio per la modalità a 32 bit utilizza prefissi di dimensioni di operando. Stessa istruzione, codifica diversa. Ma lodsbin modalità 32 bit verrà utilizzato [esi], quindi questa versione di test funziona con puntatori a 32 bit (perché non eseguiamo alcun calcolo matematico o incremento / confronto dei puntatori).

Nessuna discrepanza. Il mio cablaggio di prova stampa un messaggio in caso di mancata corrispondenza.

$ yasm -felf32 -Worphan-labels -gdwarf2 adler32-x86-16.asm -o adler32-x86-16+32.o &&
   g++ -DTEST_16BIT -m32 -std=gnu++11 -O1 -g -Wall -Wextra -o test-adler32-x16  adler32-x86-16+32.o  test-adler32.cpp -lz &&
   ./test-adler32-x16
Eagles are great! (len=17): zlib:0x36c405fe  c:0x36c405fe golfed:0x36c405fe
Programming Puzzles & Code Golf (len=31): zlib:0xbac00b2a  c:0xbac00b2a golfed:0xbac00b2a
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=32): zlib:0x040f0fc1  c:0x040f0fc1 golfed:0x040f0fc1
?????????????????????????????????????????????????? (len=1040): zlib:0x82000000  c:0x82000000 golfed:0x82000000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=4096): zlib:0xb169e06a  c:0xb169e06a golfed:0xb169e06a
(0xFF repeating) (len=4096): zlib:0x8161f0e2  c:0x8161f0e2 golfed:0x8161f0e2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=5837): zlib:0x5d2a398c  c:0x5d2a398c golfed:0x5d2a398c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=5838): zlib:0x97343a0a  c:0x97343a0a golfed:0x97343a0a
(0xFF repeating) (len=9999): zlib:0xcae9ea2c  c:0xcae9ea2c golfed:0xcae9ea2c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (len=65535): zlib:0x33bc06e5  c:0x33bc06e5 golfed:0x33bc06e5

Con i registri a 16 bit, non possiamo differire la riduzione del modulo se non dopo il ciclo. C'è una differenza interessante tra 16 bit e altre dimensioni di operandi: m = 65521( 0xFFF1) è più della metà di 65536. Sottraendo msu carry mantiene il valore inferiore a 2 * m, anche se high=0xFFF0 + 0xFFF0. Dopo il ciclo, un confronto-e-sottrazione farà il trucco, invece di un div.

Mi è venuta in mente una nuova tecnica per ridurre un registro dopo un modulo che può produrre un carry . Invece di azzerare la metà superiore dell'input per div, utilizzare setc dlper creare un dividendo a 32 bit contenente il risultato aggiuntivo non troncato ( dhè già azzerato). ( divfa divisione 32b / 16b => 16bit.)

setcc(3 byte) è stato introdotto con 386. Per eseguirlo su 286 o precedenti, il migliore che ho trovato utilizza l' istruzione non documentata salc(imposta AL da carry) . È un opcode a un byte per sbb al,al, quindi potremmo usare salc/ neg alprima di fare il xchg ax, dx(di cui abbiamo bisogno comunque). Senza salc, c'è una sequenza 4B: sbb dx,dx/ neg dx. Non possiamo usare 3B sbb dx,dx/ inc dx, perché emulerebbe setncpiuttosto che setc.


Ho provato a utilizzare la dimensione dell'operando a 32 bit invece di gestire carry, ma non sono solo le addistruzioni a richiedere un prefisso della dimensione dell'operando. Le istruzioni per impostare le costanti e così via necessitano anche di prefissi di dimensioni dell'operando, quindi non è stato il più piccolo.



2

Perl 5, 43 byte

42 byte, più 1 per -aEanziché-e

L'input è un numero intero decimale, separato da spazi.

map$h+=$.+=$_,@F;say$.%65521+$h%65521*4**8

Una punta del mio cappello a Sp3000 , da cui ho preso idee per questa risposta.

Come funziona:

  1. A causa di -a, $. inizia da 1 ed @Fè l'array di input. $hinizia da 0. $_viene utilizzato da mapcome segnaposto per ciascun elemento di un array.
  2. map$h+=$.+=$_,@Fsignifica che per ogni elemento in @Faggiungiamo quell'elemento a $.e quindi aggiungiamo $.a $h.
  3. Quindi eseguiamo l'aritmetica modulare $.%65521+$h%65521*4**8(ovvero, ($. % 65521) + ( ($h % 65521) * (4**8) )e say(stampiamo) il risultato.

1

Fattore, 112 109 103 byte

Ora , questa è una traduzione letterale dell'algoritmo nella domanda ... ora che l'ho effettivamente fatto, sai, corretto.

[ [ sum 1 + ] [ [ dup length [1,b] reverse v. ] [ length ] bi + ] bi [ 65521 mod ] bi@ 16 shift bitor ]

Ungolfed:

: adler-32 ( seq -- n )
  [ sum 1 + ] 
  [ 
    [ dup length [1,b] reverse v. ] 
    [ length ] bi + 
  ] bi 
  [ 65521 mod ] bi@ 
  16 shift bitor 
  ;

Si aspetta una sequenza di numeri o una stringa (non molta differenza, anche se tecnicamente non sono la stessa cosa).

Non so come questo funzionerà per il limite dato su una versione di Factor compilata con dimensioni di parole di 32 bit, ma sulla mia macchina da 6 GB a 64 bit a 2,2 GHz:

IN: scratchpad 1040 63 <array>

--- Data stack:
{ 63 63 63 63 63 63 63 63 63 63 63 63 63 63 ~1026 more~ }
IN: scratchpad [ adler-32 ] time
Running time: 7.326900000000001e-05 seconds

--- Data stack:
2181038080
IN: scratchpad 10,000 63 <array> 

--- Data stack:
2181038080
{ 63 63 63 63 63 63 63 63 63 63 63 63 63 63 ~9986 more~ }
IN: scratchpad [ adler-32 ] time
Running time: 0.000531669 seconds

1

Rubino, 91 byte

->s{b=s.bytes;z=i=b.size
b.inject(1,:+)%65521+b.map{|e|e*(1+i-=1)}.inject(z,:+)%65521*4**8}

1

Clojure, 109 byte

Basato sulla soluzione di @Mark Adler .

(fn f[s](->> s(reduce #(mapv + %(repeat %2)[0(first %)])[1 0])(map #(rem % 65521))(map *[1 65536])(apply +)))

Ungolfed

(fn f [s]
  (->> s
       (reduce #(mapv + % (repeat %2) [0 (first %)]) [1 0])
       (map #(rem % 65521))
       (map * [1 65536])
       (apply +)))

uso

=> (def f (fn f[s](->> s(reduce #(mapv + %(repeat %2)[0(first %)])[1 0])(map #(rem % 65521))(map *[1 65536])(apply +))))
=> (f [69 97 103 108 101 115 32 97 114 101 32 103 114 101 97 116 33])
918816254
=> (f [80 114 111 103 114 97 109 109 105 110 103 32 80 117 122 122 108 101 115 32 38 32 67 111 100 101 32 71 111 108 102])
3133147946
=> (f (repeat 32 126))
68095937
=> (f (repeat 1040 63))
2181038080
=> (f (repeat 4096 255))
2170679522

1

Javascript (130 personaggi giocati a golf)

Ungolfed

function a(b)
{
    c=1
    for(i=0;i<b.length;i++)
    {
        c+=b[i]
    }
    d=c%65521
    f=""
    e=0
    k=""
    for(j=0;j<b.length;j++)
    {
        k+= "+"+b[j]
        f+= "(1"+k+")"
        e= ((eval(f)))
        if(j!=b.length-1){f+="+"}
    }
    g=e%65521
    h=d+65536*g
    console.log(h)
}

golfed

a=b=>{for(c=1,k=f="",y=b.length,i=0;i<y;i++)c+=x=b[i],f+="(1"+(k+="+"+x)+")",i<y-1&&(f+="+");return z=65521,c%z+65536*(eval(f)%z)}

Incolla nella Developers Console e poi dagli una matrice di byte EG:

[69, 97, 103, 108, 101, 115, 32, 97, 114, 101, 32, 103, 114, 101, 97, 116, 33]

E restituirà il checksum alla console


1

TMP, 55 byte

3a1.3b0.1;4+a>T8%a>xFFF14+b>a8%b>xFFF11~5<b>164|b>a2$b$

L'implementazione in Lua è disponibile qui: http://preview.ccode.gq/projects/TMP.lua


1
Benvenuti in Puzzle di programmazione e Code Golf! Questo linguaggio soddisfa la nostra definizione di linguaggi di programmazione ?
gatto

@cat Credo di si, ma non sono sicuro che supporti davvero le "tuple?"
brianush1,

Nemmeno BrainFuck, quindi probabilmente stai bene. Se è completo, può trovare numeri primi e può fare le cose di base che qualsiasi altra lingua può fare (e può), funzionerà :) CSS non è un linguaggio di programmazione da solo e non è HTML ma CSS3 + HTML è completo e può trovare numeri primi.
cat

Quindi, va bene usare in CodeGolf?
brianush1,

Penso di sì - non conosco né TMP né Lua, quindi una spiegazione di questo codice sarebbe di grande aiuto (e renderebbe questa una grande risposta). : D
cat

1

Python 3.5, 82 byte:

( -1 byte grazie a Neil ! )

( -1 byte grazie a mathmandan ! )

( -4 byte grazie a Dennis ! )

lambda w:((1+sum(w))%65521)+4**8*(sum(1+sum(w[:i+1])for i in range(len(w)))%65521)

Una lambdafunzione anonima . Accetta un array di byte, applica l'intero algoritmo all'array e genera il risultato. Ha funzionato con successo per tutti i casi di test. Si chiama assegnando una variabile e quindi chiamando quella variabile proprio come si chiamerebbe una normale funzione. Se stai usando la shell, questo dovrebbe essere prodotto senza una funzione di stampa. Tuttavia, in caso contrario, è necessario racchiudere la chiamata di funzione inprint() funzione per visualizzare effettivamente l'output.

Provalo online! (Ideone)


(E+15)è in realtà un byte più lungo di 65536.
Neil,

@Neil Grazie per la punta. Ora è riparato.
R. Kap,

@ Sp3000 Quindi? Non importa se hanno aggiunto alcuni byte, ma il fatto che non aggiungano byte non è un problema .
R. Kap

4**8è un byte più corto di 65536.
Mathmandan,

È possibile salvare 4 byte rilasciando le parentesi attorno al generatore e ripetendo da 0 a len (w) . Altri 6 byte possono essere salvati sfruttando la precedenza dell'operatore.
Dennis,

1

Fissione , 324 byte

          /   M
       R_MZ  |S
      D ]    |S
 /?V?\} {}/  |S /    \
R{/A  Z$[/   |S/     {\
  } J{\      |S      ;_
 \^  /       |S   R'~++Y++~'L
 /    /      |S       }Y;
 \  \        ;^/
 /  /         +\+ R'~++A++~'L
 \  <Z________________/
    ;\X       //
              \Y/
               *

Attenzione, l'unica implementazione su cui ho provato questo è la mia porta del linguaggio su F #. Non è golf, soprattutto perché ho trovato più facile fare un paio di lunghe tirate mentre la mia costante primaria si è raffreddata sul fondo, quindi potrei tornare indietro e modificarla.

Come funziona?

  • Il R'~++Y++~'L blocco fonde una costante 256 e la lancia verso il basso, impostando il moltiplicatore di massa del reattore direttamente sotto di esso.
  • Il R'~++A++~'Ablocco fonde un altro 256 e lo lancia verso il reattore sopra, che fissa la particella in due multipli di 65536massa di massa ciascuno, lanciandoli a sinistra ea destra (dove la particella destra viene immediatamente distrutta dal terminatore).
  • La particella sinistra colpisce un altro reattore e subisce la fissione, dividendosi in due particelle di uguale massa che si dirigono su e giù.
  • La potenza di due particelle che viaggia verso l'alto passa attraverso una manipolazione di massa netta-zero, si riflette a sinistra, quindi imposta il moltiplicatore di massa del reattore a fusione. Questo reattore sarà il modo in cui moltiplichiamo il blocco H.
  • La particella che viaggia verso il basso si riflette a sinistra e perde massa nel lungo periodo, raggiungendo infine una massa di 65521 (il nostro grande numero primo).
  • Lo specchio rotazionale ( Z) alla fine della corsa fa sì che la particella duplichi il numero primo, rimandandone uno a destra dove alla fine imposta la massa immagazzinata del reattore a fissione ( ^). Questo è il modo in cui applicheremo l'operatore del modulo al blocco H.
  • La seconda copia viene riflessa, dove svolge una funzione analoga per il reattore a fissione (< ) che useremo per il blocco L.
  • Ora che le nostre costanti sono a posto, ci impegniamo in shenanigans in alto a sinistra per leggere i nostri input e generare i nostri due elenchi. Ad essere sincero, dimentico come funzionano, ma per la stringa vuota ho dovuto rallentare la particella di somma del blocco H, che spiega il|S "torre di raffreddamento".
  • \Y/ fonde il blocco L (che entra attraverso il canale sinistro) e il blocco H (che entra attraverso il canale destro), quindi li sbatte in un terminatore che imposta il codice di uscita sulla massa fusa.

A meno che non commetta un errore da qualche parte, questo non sembra funzionare con l'interprete ufficiale ( link ). Dove posso trovare la tua porta su F #?
Dennis,

@Dennis Sto cercando di capire se il bug è sulla mia parte o no, ma non riesco nemmeno a far funzionare l'interprete. Vedrò se riesco a farlo funzionare, quindi aggiorno la mia risposta se necessario.
Andrew Coonce,

@Dennis Sembra che l'interprete online non gestisca l'interruzione del codice di errore *, ed è così che sto restituendo l'output. Vedrò se riesco a trovare un altro interprete per verificare l'output domani.
Andrew Coonce,
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.