Calculer la somme de contrôle Adler-32

32

Contexte

Adler-32 est une somme de contrôle 32 bits inventée par Mark Adler en 1995 qui fait partie de la bibliothèque zlib largement utilisée (également développée par Adler). Adler-32 n'est pas aussi fiable qu'un contrôle de redondance cyclique 32 bits , mais - au moins dans le logiciel - il est beaucoup plus rapide et plus facile à mettre en œuvre.

Définition

Soit B = [b 1 , ⋯, b n ] un tableau d'octets.

La somme de contrôle Adler-32 de B est définie comme le résultat de bas + 65536 × haut , où:

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

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

Tâche

Étant donné un tableau d'octets en entrée, calculez et renvoyez sa somme de contrôle Adler-32, en respectant ce qui suit.

  • Vous pouvez prendre l'entrée comme un tableau d'octets ou d'entiers, ou comme une chaîne.

    Dans les deux cas, seuls les octets correspondant aux caractères ASCII imprimables apparaîtront dans l'entrée.

    Vous pouvez supposer que la longueur de l'entrée satisfera 0 <longueur ≤ 4096 .

  • Si vous choisissez d'imprimer la sortie, vous pouvez utiliser n'importe quelle base positive jusqu'à 256 inclus.

    Si vous choisissez unaire, assurez-vous que l'interpréteur peut gérer jusqu'à 2 32 - 983056 octets de sortie sur une machine avec 16 Gio de RAM.

  • Les éléments intégrés qui calculent la somme de contrôle Adler-32 sont interdits.

  • Les règles de standard s'appliquent.

Cas de 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
Dennis
la source
7
Je noterai que beaucoup de réponses ici échoueront avec des séquences d'entrée grandes ou très grandes lorsqu'elles déborderont les sommes entières 32 ou 64 bits, en raison du report de l'opération modulo jusqu'à ce que les sommes soient calculées. Une mise en œuvre vraiment conforme devrait faire l'opération modulo au moins périodiquement pour empêcher les sommes de déborder. Un entier signé 32 bits déborderait après seulement 4096 0xff. Un entier signé 64 bits déborderait après 256 Mio de 0xff.
Mark Adler
@MarkAdler Hm, juste point. Comme je n'ai pas spécifié que les solutions devraient fonctionner pour des chaînes arbitrairement longues et que je ne veux pas invalider les réponses existantes, je vais définir une limite pour la longueur de l'entrée.
Dennis
@MarkAdler Je ne pense pas que ce soit important. Je suis assez certain qu'un débordement (entiers 32 bits signés) ne peut se produire qu'avec 4104 octets ou plus d'entrée, car la valeur maximale de high avant le modulo est n * (n + 1) / 2 * 255 + n . En plus de cela, le défi limite l'entrée aux octets correspondant aux caractères ASCII imprimables.
Dennis
Nous pourrions également permettre aux langues de déborder leurs types numériques et d'exiger uniquement que le résultat renvoyé soit équivalent, en tenant compte du débordement, au résultat correct.
miles
1
@PeterCordes Oui, les tableaux d'entiers 32 bits sont parfaitement bien. Au moins à mon avis, les soumissions devraient se concentrer sur le golf de l'algorithme et accorder le moins d'attention possible aux E / S.
Dennis

Réponses:

3

Gelée, 19 17 octets

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

Essayez-le en ligne!

+\,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
Fuite, nonne
la source
Mieux encore:⁹²¤
Dennis
1
@Dennis J'ai alors surclassé vos 18 octets.
Leaky Nun
1
Eh bien, vous avez surclassé ..
Leaky Nun
64

Mathematica, 46 octets

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

Une fonction anonyme qui prend un tableau entier et renvoie l'Adler-32, avec quelques améliorations de miles et Martin (voir commentaires).

miles 'est également de 46 octets , mais plus rapide:

{1,4^8}.{Tr@#+1,Tr[Accumulate@#+1]}~Mod~65521&
Mark Adler
la source
37
... Vous venez de jouer à votre propre algorithme célèbre?
Mego
25
Pardonnez-moi si je suis un peu frappé par les étoiles. Ce n'est pas tous les jours que vous voyez un si grand nom en génie logiciel sur notre humble petit site. Bienvenue à bord!
Mego
6
Pas si gros que ça.
Mark Adler
3
Si vous voulez dire moi, c'est la première fois que je pense à implémenter Adler-32 dans Mathematica.
Mark Adler
9
Ou peut-être avez-vous préparé cette solution depuis que vous avez rejoint Code Golf, en attendant simplement qu'on vous la demande. "Finalement!" ;-)
Antti Haapala
13

Julia, 73 46 octets

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

Il s'agit d'une fonction anonyme qui accepte un tableau et renvoie un entier. Pour l'appeler, assignez-le à une variable.

Nous combinons sum(x) + 1et sum(cumsum(x) + 1)dans un tableau, où xest le tableau d'entrée, et prenons chaque module 65521. Nous calculons ensuite le produit scalaire avec 1 et 4 8 , ce qui nous donne (sum(x) + 1) + 4^8 * sum(cumsum(x) + 1), qui est exactement la formule Adler-32.

Essayez-le en ligne! (Comprend tous les cas de test)

Enregistré 27 octets grâce à Sp3000 et Dennis!

Alex A.
la source
Wow, c'est vraiment intelligent.
chat
@cat J'ai Sp3000 et Dennis à remercier pour la plupart de leur intelligence. :)
Alex A.
11

Fonction de code machine x86-64: 33 32 octets (ou 31 30 octets avec une int[]entrée au lieu de char[])

Fonction de code machine x86-32: 31 octets

En tant que fragment de code asm en ligne GNU C: enregistre 2B 1B (juste l' retinsn).

Source commentée et pilote de test sur github

La version 64 bits peut être appelée directement à partir de C avec le System V x86-64 ABI standard (en utilisant 2 arguments factices pour obtenir des arguments dans les paramètres que je veux). Les conventions d'appel personnalisées ne sont pas rares pour le code asm, c'est donc une fonctionnalité bonus.

Le code machine 32 bits enregistre 1B, car la fusion des moitiés haute et basse push16/push16 => pop32ne fonctionne qu'en mode 32 bits. Une fonction 32 bits aurait besoin d'une convention d'appel personnalisée. Nous ne devrions pas lui en vouloir, mais appeler à partir de C nécessite une fonction wrapper.

Après le traitement de 4096 ~(ASCII 126) octets, high = 0x3f040000, low = 0x7e001. Donc , highn'est pas encore défini de » bit le plus significatif. Mon code en profite, se prolongeant eaxdans edx:eaxavec cdqcomme moyen de mise à zéro 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 octets.


Source NASM commentée:

des trucs:

  • xchg eax, r32est un octet; moins cher que mov. 8086 avait besoin de données dans ax pour beaucoup plus de choses que> = 386, alors ils ont décidé de dépenser beaucoup d'espace opcode sur le désormais rarement utilisé xchg ax, r16.

  • Le mélange de push64 et push16 pour fusionner haut et bas dans un seul registre enregistre les instructions de mouvement des données reg-reg autour de deux divs. La version 32 bits de cette astuce fonctionne encore mieux: push16 / push16 / pop32n'est que de 5 milliards au total, pas de 6.

Puisque nous poussons / pop, ce n'est pas sûr pour asm en ligne dans le SysV amd64 ABI (avec une zone rouge) .

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:

J'ai également envisagé d'utiliser rcxcomme index de tableau, au lieu d'avoir deux compteurs de boucle, mais adler32 (s)! = Adler32 (reverse (s)). Nous ne pouvions donc pas utiliser loop. Compter de -len vers zéro et utiliser movzx r32, [rsi+rcx]utilise simplement trop d'octets.

Si nous voulons envisager d'incrémenter le pointeur nous-mêmes, le code 32 bits est probablement le chemin à parcourir. Même l'ABI x32 (pointeurs 32 bits) n'est pas suffisant, car il inc esis'agit de 2B sur amd64, mais de 1B sur i386. Il semble difficile de battre xor eax,eax/ lodsb/ loop: 4B au total pour que chaque élément à son tour soit étendu à zéro en eax. inc esi/ movzx r32, byte [esi]/ loopest 5B.

scasest une autre option pour incrémenter un pointeur avec une instruction 1B en mode 64 bits. ( rdi/ ediau lieu de rsi, nous prenons donc l'argument du pointeur rdi). scasCependant, nous ne pouvons pas utiliser le résultat de l'indicateur comme une condition de boucle, car nous ne voulons pas conserver la mise à zéro de l'eax. Une allocation de registre différente pourrait peut-être enregistrer un octet après la boucle.


int[] contribution

La prise de fonction complète uint8_t[]est la réponse «principale», car c'est un défi plus intéressant. Décompresser int[]est une chose déraisonnable de demander à notre appelant de le faire dans cette langue, mais cela économise 2B.

Si nous prenons notre entrée comme un tableau décompressé d'entiers 32 bits, nous pouvons enregistrer facilement un octet (utiliser lodsdet remplacer xor eax,eax / cdqpar juste xor edx,edx).

Nous pouvons enregistrer un autre octet en mettant à zéro edx avec lodsd/ cdqet en réorganisant la boucle afin qu'elle charge l'élément de terminaison 0 avant de quitter. (Nous supposons toujours qu'il existe, même s'il s'agit d'un tableau de int, pas d'une chaîne).

; 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

J'ai également fait une version non testée qui utilise scasd(version 1B de add edi,4) et add eax, [rdi]au lieu de lodsd, mais c'est aussi 30 octets. Les économies highrésultant de la présence d'EAX à la fin de la boucle sont compensées par un code plus large ailleurs. Il a l'avantage de ne pas dépendre d'un 0élément de terminaison dans l'entrée, ce qui est peut-être déraisonnable pour un tableau décompressé où la longueur nous est également donnée explicitement.


Pilote de test C ++ 11

Voir le lien github. Cette réponse devenait trop importante, et le pilote de test a obtenu plus de fonctionnalités avec un code plus gros.

Peter Cordes
la source
2
J'ai autorisé des entiers au lieu d'octets principalement parce que de nombreuses langues n'ont même pas de type d'octet. Les entiers 32 bits peuvent être un choix contre nature pour l'assemblage, mais le golf de code consiste à extraire le dernier octet tout en respectant les règles. Si un choix "contre nature" conduit à un nombre d'octets inférieur, je dirais que c'est parti.
Dennis
@Dennis: Je comprends la nécessité de la règle pour certaines langues. Je souhaite qu'il y ait un moyen pour la règle de vous laisser utiliser uniquement int[]si cela était nécessaire, ou si vous avez enregistré plus de 4 octets de code ou quelque chose. Je n'ai aucun problème à présenter une solution au adler32(int[])problème, mais je pense que le adler32(char[])problème est plus intéressant, car c'est la vraie fonction adler32. C'est ce que je veux vraiment jouer au golf en asm. (Et j'aimerais beaucoup économiser un octet de plus, car dans la vraie vie, 33 octets = 48 octets si la fonction suivante utilise ALIGN 16). Je suppose que je continuerai à jouer au golf à la fois.
Peter Cordes
@Dennis: aussi, devons-nous gérer le cas len = 0? J'économise 2B en utilisant un do{}while(--len)style de boucle au lieu d'un while(len--){}.
Peter Cordes
4
En ce qui concerne les explications, plus elles sont détaillées, mieux c'est.
Dennis
3
@cat: Non, je ne trouve pas l'asme douloureux. Je ne passerais pas mon temps à écrire des réponses Stackoverflow aux questions asm / performance et à mettre à jour le wiki de la balise x86 si je le faisais: P Si vous voulez savoir pourquoi le code s'exécute lentement ou rapidement, vous devez regarder et comprendre l'asm. Une fois que vous avez fait cela pendant un certain temps, vous commencez à voir quand le compilateur aurait pu faire du code plus rapidement ... et finalement vous commencez à réfléchir à la façon dont le compilateur pourrait compiler du code au fur et à mesure que vous l'écrivez. L'optimisation de la taille du code au lieu des performances est parfois un changement intéressant.
Peter Cordes
8

MATL , 22 octets

tsQwYsQsh16W15-\l8Mh*s

L'entrée peut être un tableau de nombres ou la chaîne ASCII correspondante.

Essayez-le en ligne!

Explication

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
Luis Mendo
la source
7

En fait, 36 octets

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

Essayez-le en ligne!

Explication:

;Σ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]
Mego
la source
7

Java, 84 octets

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

Si les solutions Java sont toujours censées être du code compilable complet, faites-le moi savoir.

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

Remarque

Vous devrez convertir l'entrée Stringen int[]( int[]est un octet plus court que byte[]ou char[]).

Sortie

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
Marv
la source
1
Bonne réponse, et bienvenue sur le site! En outre, les solutions qui ne sont pas complètes et compilables sont correctes, sauf si le défi indique explicitement qu'il devrait s'agir d'un programme complet. C'est une fonction complète, donc ça compte.
DJMcMayhem
6

Piet, 120 Codels codelsize 1

Avec codelsize 20:

codelsize 20

Notes / Comment ça marche?

  • Puisqu'il n'est pas possible d'utiliser un tableau ou une chaîne en entrée, ce programme fonctionne en prenant une série d'entiers (représentant des caractères ascii) en entrée. J'ai pensé à utiliser des entrées de caractères au début, mais j'ai eu du mal à trouver une bonne solution pour la terminaison, alors maintenant il se termine quand un nombre inférieur à 1 est entré. Ce n'était à l'origine que des valeurs négatives pour la terminaison, mais j'ai dû changer l'initialisation après avoir écrit le programme, donc maintenant je ne peux pas ajuster la valeur requise2 , seulement un 1(26/45 sur l'image de trace). Cela n'a pas d'importance, car selon les règles du défi, seuls les caractères ascii imprimables sont autorisés.

  • J'ai longtemps lutté pour rentrer dans la boucle, même si j'ai finalement trouvé la solution la plus élégante. Non pointerou switchopérations, seul l'interprète se heurte aux murs jusqu'à ce qu'il revienne dans le codel vert pour lire l'entrée (43-> 44 sur les images de trace).

  • La terminaison de boucle est obtenue en dupliquant d'abord l'entrée, en ajoutant 1 puis en vérifiant si elle est supérieure à 1. Si c'est le cas, le sélecteur de codel est déclenché et l'exécution se poursuit sur le chemin inférieur. Si ce n'est pas le cas, le programme continue à gauche (codels jaune vif, 31/50 sur les images traces).

  • La taille d'entrée prise en charge dépend de la mise en œuvre de l'interpréteur, bien qu'il soit possible de prendre en charge une entrée arbitrairement grande avec le bon interprète (par exemple, un interpréteur Java qui utilise BigIntegercomme valeurs internes)

  • Je viens de voir que la configuration comprend un inutile DUPet CC(7-> 8-> 9 dans les images de trace). Je ne sais pas comment cela s'est produit. C'est effectivement un noop cependant, il bascule le sélecteur de codel 16 fois, ce qui n'entraîne aucun changement.

Images de trace Npiet

Configuration et première boucle:

starttrace

Terminaison, sortie et sortie de boucle:

endtrace

Les sorties

Pardonnez-moi si je n'inclus qu'une seule sortie, cela prend juste beaucoup de temps pour entrer: ^)

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

Trace Npiet pour [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):
Marv
la source
5

C89, 70 octets

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

Pour tester (compiler avec 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;
}
orlp
la source
Est-ce à cela que zlibressemble la source? Hm ...
chat
1
Cette implémentation a fait un bon point de départ pour ma version asm x86.
Peter Cordes
Peut enregistrer 1 octet en utilisant forau lieu de while:for(h=0,l=1;*B;)h+=l+=*B++;
ninjalj
5

Labyrinthe , 37 36 32 31 octets

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

Essayez-le en ligne!

Entrée sous forme de liste d'entiers. Le programme se termine avec une erreur (dont le message d'erreur va à STDERR).

Explication

Primaire labyrinthe:

  • Labyrinth a deux piles d'entiers de précision arbitraire, principale et aux (iliaire), qui sont initialement remplis d'une quantité infinie (implicite) de zéros.
  • Le code source ressemble à un labyrinthe, où le pointeur d'instruction (IP) suit les couloirs quand il le peut (même dans les coins). Le code commence au premier caractère valide dans l'ordre de lecture, c'est-à-dire dans le coin supérieur gauche dans ce cas. Lorsque l'IP arrive à n'importe quelle forme de jonction (c'est-à-dire plusieurs cellules adjacentes en plus de celle dont elle est issue), elle choisira une direction basée sur le haut de la pile principale. Les règles de base sont les suivantes: tourner à gauche lorsque négatif, continuer à avancer à zéro, tourner à droite lorsqu'il est positif. Et lorsque l'un d'eux n'est pas possible parce qu'il y a un mur, l'IP prendra la direction opposée. L'IP se retourne également en cas d'impasse.
  • Les chiffres sont traités en multipliant le haut de la pile principale par 10, puis en ajoutant le chiffre. Pour commencer un nouveau numéro, vous pouvez pousser un zéro avec _.

Bien que le code commence par une "pièce" 4x2, il s'agit en fait de deux boucles deux par deux séparées serrées ensemble. Il se trouve que l'IP se limite à une boucle à la fois en raison des valeurs de la pile.

Le code commence donc par une boucle 2x2 (dans le sens des aiguilles d'une montre) qui lit l'entrée lors du calcul des sommes de préfixe:

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

Maintenant, nous avons toutes les sommes de préfixe sur la pile aux , ainsi qu'une copie de la somme sur toutes les valeurs et de l' 0EOF sur la main . Avec cela, nous entrons dans une autre boucle 2x2 (dans le sens des aiguilles d'une montre) qui additionne toutes les sommes de préfixe à calculer 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.

La pile principale a maintenant LOW - 1et HIGHet zéro, sauf que nous n'avons pas encore pris le modulo. Le reste du code est complètement linéaire:

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 atteint désormais une impasse et se retourne. Le +et *sont essentiellement sans opération, en raison des zéros au bas de la pile. Le 36transforme maintenant le haut du principal en 63, mais les deux {{tirent deux zéros de aux sur le dessus. %Essaie ensuite de diviser par zéro, ce qui met fin au programme.

Notez que Labyrinth utilise des entiers de précision arbitraire, donc le report du modulo jusqu'à la fin de la somme ne causera pas de problèmes de dépassement d'entier.

Martin Ender
la source
5

Python 2, 60 58 octets

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

Une approche assez simple. Il s'agit d'un programme complet qui prend une liste d'entiers via STDIN, par exemple [72, 105, 33].

(Merci à @xnor pour l'incroyable astuce d'aliasing / initialisation)

Sp3000
la source
2
Vous pouvez faire H=h=65521pour initialiser hen créant un alias 65521.
xnor
4

J, 30 octets

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

Cela pourrait probablement être condensé davantage avec un train différent.

Usage

Ici x $ ycrée une liste avec des xcopies de 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

Explication

+/(+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
milles
la source
4

Octave, 52 50 octets

Sauvegardé 2 octets grâce à @LuisMendo

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

Prend un tableau d'entiers en entrée.

bas est tiré du dernier élément de haut (avant sommation) plutôt que de calculer la somme explicitement, économisant un grand total de ... 1 octet !

Exemple de run sur ideone .

gobelet
la source
@LuisMendo Ooh, j'ai oublié +B. Je suppose que la spécification d'entrée indique que vous pouvez prendre des entiers, alors je vais peut-être le faire.
bécher
3

CJam, 30 29 octets

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

Entrée sous forme de liste d'entiers.

Testez-le ici.

Explication

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.
Martin Ender
la source
3

Perl 6 , 60 octets

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

Explication:

{
  # $_ 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
  )
}

Tester:

#! /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
Brad Gilbert b2gills
la source
3

Python 3 (79 octets)

Basé sur la solution de R. Kap.

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

J'ai remplacé la multiplication par un décalage et retiré une paire de supports.

Parce que je ne peux pas poster de commentaires, j'ai fait une nouvelle réponse.

R2D2
la source
3

Schéma, 195 octets

(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))))))))

S'il n'y avait pas toutes ces parenthèses ...

Numeri dit Réintégrer Monica
la source
3

Haskell, 54 50 octets

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

Exemple d'utilisation: g [69,97,103,108,101,115,32,97,114,101,32,103,114,101,97,116,33]-> 918816254.

scanlinclut la valeur de départ (-> 1) dans la liste (-> [1,1+b1,1+b1+b2,..]), donc le sumest désactivé par 1, qui est fixé en ajoutant -1à la liste avant la sommation.

Edit: Merci @xnor pour 4 octets.

nimi
la source
Il semble que vous pouvez extraire le sommateur dans m: m=(`mod`65521).sum g x=m(-1:scanl(+)1x)*4^8+m(1:x). Il y a probablement une meilleure façon de fixer les sommes que de payer par anticipation.
xnor
3

JavaScript (ES7), 52 50 octets

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

ES6 prend 51 octets (remplacez 4 ** 8 par 65536). Si vous voulez une version chaîne, alors pour 69 octets:

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

Edit: sauvé 2 octets grâce à @ user81655.

Neil
la source
3

Fonction ARM Thumb-2 acceptant uint8_t[]: 40 octets (36B pour ABI non standard etint[] )

Caractéristiques: modulo non différé, donc les entrées de taille arbitraire conviennent. N'utilise pas réellement l'instruction de division, donc ce n'est pas lent. (euh, du moins pas pour cette raison: P)

Économies grâce aux règles moins strictes suivantes:

  • -2B si nous n'avons pas besoin de sauvegarder les registres avant de les utiliser.
  • -2B pour obliger l'appelant à décompresser les octets dans un uint32_t[]tableau.

Donc, le meilleur cas est 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 octets


Remarques:

Au lieu de log%mla fin, nous faisons if(low>=m) low-=mà l'intérieur de la boucle. Si nous faisons bas avant haut, nous savons que ni l'un ni l'autre ne peut dépasser 2*m, donc le modulo est juste une question de soustraction ou non. A cmpet subprédéfini n'est que 6B en mode Thumb2. L'idiome standard pour% est 8B en mode Thumb2:

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

La adler(char *)version de longueur implicite a la même taille de code que la longueur expliciteadler(uint8_t[], uint32_t len) . Nous pouvons définir des indicateurs pour la condition de sortie de boucle avec une seule instruction 2B dans les deux cas.

La version de longueur implicite a l'avantage de fonctionner correctement avec la chaîne vide, au lieu d'essayer de boucler 2 ^ 32 fois.


assembler / compiler avec:

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

ou

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

Sans -static, le processus exécuté sous qemu-armn'a pas trouvé son éditeur de liens dynamique. (Et oui, j'installe un ARM configuration inter-devel juste pour cette réponse, parce que je pensais que mon idée était fondée-Soustraire propre.) Sur amd64 Ubuntu, installer gcc-arm-linux-gnueabi, g++-arm-linux-gnueabi. J'ai trouvé une gdb-arm-none-eabisorte de connexion à peine travaillée qemu-arm -g port.

Source commentée:

// 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.cppa les mêmes cas de test et main()que pour ma réponse x86-64, mais commence de cette façon:

#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
Peter Cordes
la source
3

Fonction de code machine x86 16 bits: 32 octets à l'aide d'une convention d'appel personnalisée

Args dans les registres et ne préservant pas les regs autres que bp (et sp).

En code 16 bits, nous renvoyons une valeur 32 bits dans la dx:axpaire de registres. Cela signifie que nous ne doivent pas passer des instructions de fusion highet lowen eax. (Cela permettrait également d'économiser des octets en code 32 et 64 bits, mais nous ne pouvons justifier le déchargement de ce travail vers l'appelant qu'en code 16 bits.)

Source commentée et pilote de test sur github (pour x86 16, 32 et 64 bits et 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 octets

Testé en assemblant le même code pour le mode 32 bits, donc je peux l'appeler (avec une fonction wrapper) à partir de C compilé avec -m32. Pour moi, le mode 16 bits est quelque peu intéressant, les appels système DOS ne le sont pas. Toutes les instructions ont des opérandes explicites, sauf loopetlodsb , donc l'assemblage pour le mode 32 bits utilise des préfixes de taille d'opérande. Même instruction, encodage différent. Mais lodsben mode 32 bits, il sera utilisé [esi], donc cette version de test fonctionne avec des pointeurs 32 bits (car nous ne faisons pas de calcul d'adresse ou d'incrémentation / comparaison de pointeur).

Aucun décalage. Mon harnais de test imprime un message en cas de non-concordance.

$ 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

Avec les registres 16 bits, nous ne pouvons reporter la réduction du module qu'après la boucle. Il y a une différence intéressante entre 16 bits et les autres tailles d'opérande: m = 65521( 0xFFF1) est plus de la moitié de 65536. La soustraction mau report conserve la valeur en dessous de 2 * m, même sihigh=0xFFF0 + 0xFFF0 . Après la boucle, une comparaison et une soustraction feront l'affaire, au lieu de a div.

J'ai trouvé une nouvelle technique pour réduire un registre modulo après un ajout qui peut produire un report . Au lieu de mettre à zéro la moitié supérieure de l'entrée pour div, utilisez setc dlpour créer un dividende de 32 bits contenant le résultat de l'addition non tronqué ( dhest déjà mis à zéro). ( div32b / 16b => division 16 bits.)

setcc(3 octets) a été introduit avec 386. Pour exécuter ceci sur 286 ou plus tôt, le meilleur que j'ai trouvé utilise l' instruction non documentée salc(set AL from carry) . C'est un opcode à un octet pour sbb al,al, donc nous pourrions utiliser salc/ neg alavant de faire le xchg ax, dx(dont nous avons besoin de toute façon). Sans salc, il y a une séquence 4B: sbb dx,dx/ neg dx. Nous ne pouvons pas utiliser 3B sbb dx,dx/ inc dx, car cela émulerait setncplutôt quesetc .


J'ai essayé d' utiliser une taille d'opérande de 32 bits au lieu de gérer le report, mais ce ne sont pas seulement les addinstructions qui nécessitent un préfixe de taille d'opérande. Les instructions de configuration des constantes et ainsi de suite ont également besoin de préfixes de taille d'opérande, donc ce n'est pas le plus petit.

Peter Cordes
la source
2

Perl 5, 43 octets

42 octets, plus 1 pour -aEau lieu de-e

L'entrée est sous forme d'entiers décimaux, séparés par des espaces.

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

Un petit coup de chapeau à Sp3000 , de qui j'ai pris des idées pour cette réponse.

Comment ça marche:

  1. En raison de -a, $. commence à 1 et @Fest le tableau d'entrée. $hcommence à 0. $_est utilisé parmap comme espace réservé pour chaque élément d'un tableau.
  2. map$h+=$.+=$_,@Fsignifie que pour chaque élément, @Fnous ajoutons cet élément à $.puis ajoutons $.à $h.
  3. Ensuite, nous faisons l'arithmétique modulaire $.%65521+$h%65521*4**8(c'est-à-dire ($. % 65521) + ( ($h % 65521) * (4**8) )et say(imprimons) le résultat.
msh210
la source
1

Facteur, 112 109 103 octets

Maintenant , c'est une traduction littérale de l'algorithme dans la question ... maintenant que je l'ai fait, vous savez, correct.

[ [ 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 
  ;

Attend n'importe quelle séquence de nombres ou une chaîne (pas beaucoup de différence, bien qu'ils ne soient pas techniquement les mêmes).

Je ne sais pas comment cela fonctionnera pour la limite donnée sur une version de Factor compilée avec une taille de mot de 32 bits, mais sur ma machine 6 Go 64 bits 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
chat
la source
1

Rubis, 91 octets

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

Clojure, 109 octets

Basé sur la solution de @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 +)))

Usage

=> (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
milles
la source
1

Javascript (130 personnages joués)

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

Golfé

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

Collez dans Developers Console, puis donnez-lui un tableau d'octets EG:

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

Et il retournera la somme de contrôle à la console

Shubshub
la source
1

TMP, 55 octets

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

L'implémentation dans Lua peut être trouvée ici: http://preview.ccode.gq/projects/TMP.lua

brianush1
la source
1
Bienvenue dans Programmation d'énigmes et Code Golf! Ce langage satisfait-il notre définition des langages de programmation ?
chat
@cat Je crois que oui, mais je ne sais pas s'il prend vraiment en charge les "tuples"?
brianush1
BrainFuck non plus, donc vous êtes probablement d'accord. S'il est complet, peut trouver des nombres premiers et peut faire les choses de base que tout autre langage peut faire (et il peut), cela fonctionnera :) CSS n'est pas un langage de programmation en soi et HTML non plus, mais CSS3 + HTML est turing-complete et peut trouver des nombres premiers.
cat
Alors, est-ce correct d'utiliser dans CodeGolf?
brianush1
Je pense que oui - je ne connais ni TMP ni Lua, donc une explication de ce code serait d'une grande aide (et en ferait une excellente réponse). : D
cat
1

Python 3.5, 82 octets:

( -1 octet grâce à Neil ! )

( -1 octet grâce à mathmandan ! )

( -4 octets grâce à Dennis ! )

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

Une lambdafonction anonyme . Accepte un tableau d'octets, applique l'intégralité de l'algorithme au tableau et génère le résultat. A travaillé avec succès pour tous les cas de test. Vous appelez cela en lui affectant une variable, puis en appelant cette variable comme vous appelleriez une fonction normale. Si vous utilisez le shell, cela devrait sortir sans fonction d'impression. Cependant, si vous ne l'êtes pas, vous devez encapsuler l'appel de fonction dans la print()fonction pour voir réellement la sortie.

Essayez-le en ligne! (Idéone)

R. Kap
la source
(E+15)est en fait un octet plus long que 65536.
Neil
@Neil Merci pour l'astuce. C'est corrigé maintenant.
R. Kap
@ Sp3000 Alors? Il importerait qu'ils ajoutent quelques octets, mais le fait qu'ils n'ajoutent aucun octet me convient parfaitement.
R. Kap
4**8est un octet plus court que 65536.
mathmandan
Vous pouvez économiser 4 octets en supprimant les crochets autour du générateur et en itérant de 0 à len (w) . 6 autres octets peuvent être enregistrés en exploitant la priorité des opérateurs.
Dennis
1

Fission , 324 octets

          /   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/
               *

Juste avertissement, la seule implémentation sur laquelle j'ai testé ceci est mon propre portage du langage vers F #. Ce n'est pas du golf, principalement parce que j'ai trouvé plus facile de faire de longues courses pendant que ma constante principale refroidissait le long du fond, donc je peux revenir et la peaufiner.

Comment ça marche?

  • le R'~++Y++~'L bloc fusionne une constante 256 et le lance vers le bas, en plaçant le multiplicateur de masse du réacteur directement en dessous.
  • Le R'~++A++~'Abloc en fusionne 256 autres et le lance vers le réacteur au-dessus, qui fissionne la particule en deux multiples de masse de65536 masse masse chacun, les lançant à gauche et à droite (où la particule droite est immédiatement détruite par le terminateur).
  • La particule gauche frappe un autre réacteur et subit une fission, se divisant en deux particules de masse égale montant et descendant.
  • La puissance de deux particules se déplaçant vers le haut passe par une manipulation de masse nette nulle, se réfléchit vers la gauche, puis définit le multiplicateur de masse du réacteur de fusion. Ce réacteur sera la façon dont nous multiplions le bloc H.
  • La particule se déplaçant vers le bas se réfléchit vers la gauche et perd de la masse à long terme, atteignant finalement une masse de 65521 (notre grand nombre premier).
  • Le miroir de rotation ( Z) à la fin de l'analyse fait en sorte que la particule duplique l'amorce, en renvoyant une vers la droite où elle définit finalement la masse stockée du réacteur à fission (^ ). C'est ainsi que nous appliquerons l'opérateur de module au bloc H.
  • La deuxième copie est réfléchie, où elle remplit une fonction analogue pour le réacteur à fission ( <) que nous utiliserons pour le bloc L.
  • Maintenant que nos constantes sont en place, nous nous engageons dans des manigances en haut à gauche pour lire notre entrée et générer nos deux listes. Pour être honnête, j'oublie leur fonctionnement, mais pour la chaîne vide, j'ai dû ralentir la particule sommatrice du bloc H, ce qui explique la |S"tour de refroidissement".
  • \Y/ fusionne le bloc L (qui entre par le canal gauche) et le bloc H (qui arrive par le canal droit), puis les claque dans un terminateur qui définit le code de sortie sur la masse fusionnée.
Andrew Coonce
la source
À moins que je ne fasse une erreur quelque part, cela ne semble pas fonctionner avec l'interprète officiel ( lien ). Où pourrais-je obtenir votre port en F #?
Dennis
@Dennis J'essaie de comprendre si le bogue est de mon côté ou non, mais je ne peux pas faire fonctionner l'interprète non plus. Je vais voir si je peux le faire fonctionner puis mettre à jour ma réponse si besoin est.
Andrew Coonce
@Dennis Il semble que l'interpréteur en ligne ne gère pas les abandons de code d'erreur *, c'est ainsi que je renvoie la sortie. Je vais voir si je peux trouver un autre interprète pour vérifier la sortie demain.
Andrew Coonce