Calcule la suma de comprobación Adler-32

32

Fondo

Adler-32 es una suma de verificación de 32 bits inventada por Mark Adler en 1995 que forma parte de la biblioteca zlib ampliamente utilizada (también desarrollada por Adler). Adler-32 no es tan confiable como una verificación de redundancia cíclica de 32 bits , pero, al menos en software, es mucho más rápido y fácil de implementar.

Definición

Sea B = [b 1 , ⋯, b n ] una matriz de bytes.

La suma de comprobación Adler-32 de B se define como el resultado de bajo + 65536 × alto , donde:

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

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

Tarea

Dada una matriz de bytes como entrada, calcule y devuelva su suma de comprobación Adler-32, respetando lo siguiente.

  • Puede tomar la entrada como una matriz de bytes o enteros, o como una cadena.

    En ambos casos, solo los bytes correspondientes a caracteres ASCII imprimibles aparecerán en la entrada.

    Puede suponer que la longitud de la entrada satisfará 0 <longitud ≤ 4096 .

  • Si elige imprimir la salida, puede usar cualquier base positiva hasta 256 inclusive.

    Si elige unario, asegúrese de que el intérprete pueda manejar hasta 2 32 - 983056 bytes de salida en una máquina con 16 GiB de RAM.

  • Las incorporaciones que calculan la suma de comprobación Adler-32 están prohibidas.

  • Aplican reglas estándar de .

Casos de prueba

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
fuente
77
Notaré que muchas de las respuestas aquí fallarán con secuencias de entrada grandes o muy grandes cuando desborden las sumas enteras de 32 o 64 bits, debido a diferir la operación del módulo hasta después de que se computen las sumas. Una implementación verdaderamente compatible necesitaría realizar la operación de módulo al menos periódicamente para evitar que las sumas se desborden. Un entero con signo de 32 bits se desbordaría después de solo 4096 0xff. Un entero con signo de 64 bits se desbordaría después de 256 MiB de 0xff.
Mark Adler
@ MarkAdler Hm, punto justo. Como no especifiqué que las soluciones tendrían que funcionar para cadenas arbitrariamente largas y no quiero invalidar las respuestas existentes, estableceré un límite para la longitud de la entrada.
Dennis
@ MarkAdler No creo que importe. Estoy bastante seguro de que el desbordamiento (enteros de 32 bits con signo) solo puede ocurrir con 4104 o más bytes de entrada, ya que el valor máximo de high antes del módulo es n * (n + 1) / 2 * 255 + n . Además de eso, el desafío restringe la entrada a bytes correspondientes a caracteres ASCII imprimibles.
Dennis
También podríamos permitir que los idiomas desborden sus tipos numéricos, y solo exigir que el resultado devuelto sea equivalente, teniendo en cuenta el desbordamiento, al resultado correcto.
millas
1
@PeterCordes Sí, las matrices de entradas de 32 bits son perfectas. Al menos en mi opinión, las presentaciones deben centrarse en jugar al algoritmo y prestar la menor atención posible a las E / S.
Dennis

Respuestas:

3

Jalea, 19 17 bytes

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

Pruébalo en línea!

+\,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
Monja permeable
fuente
Mejor aún:⁹²¤
Dennis
1
@ Dennis He superado tu 18-byte entonces.
Leaky Nun
1
Bueno, te has superado ...
Leaky Nun
64

Mathematica, 46 bytes

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

Una función anónima que toma una matriz entera y devuelve el Adler-32, con algunas mejoras de miles y Martin (ver comentarios).

millas 'también es de 46 bytes , pero más rápido:

{1,4^8}.{Tr@#+1,Tr[Accumulate@#+1]}~Mod~65521&
Mark Adler
fuente
37
... ¿Acabas de jugar tu propio algoritmo famoso?
Mego
25
Perdóname si estoy un poco asustado. No todos los días ves un nombre tan grande en ingeniería de software en nuestro humilde y pequeño sitio. ¡Bienvenido a bordo!
Mego
66
No tan grande.
Mark Adler
3
Si te refieres a mí, esta es la primera vez que pienso en implementar Adler-32 en Mathematica.
Mark Adler
99
O tal vez tenga esta solución lista desde que se unió a Code Golf, solo esperando que se le pregunte. "¡Finalmente!" ;-)
Antti Haapala
13

Julia, 73 46 bytes

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

Esta es una función anónima que acepta una matriz y devuelve un entero. Para llamarlo, asígnelo a una variable.

Combinamos sum(x) + 1y formamos sum(cumsum(x) + 1)una matriz, donde xestá la matriz de entrada, y tomamos cada módulo 65521. Luego calculamos el producto punto con 1 y 4 8 , lo que nos da (sum(x) + 1) + 4^8 * sum(cumsum(x) + 1), que es exactamente la fórmula Adler-32.

Pruébalo en línea! (Incluye todos los casos de prueba)

¡Ahorró 27 bytes gracias a Sp3000 y Dennis!

Alex A.
fuente
Wow, eso es muy inteligente.
gato
@cat Tengo que agradecer a Sp3000 y Dennis por la mayor parte de la inteligencia. :)
Alex A.
11

Función de código de máquina x86-64: 33 32 bytes (o 31 30 bytes con una int[]entrada en lugar de char[])

Función de código de máquina x86-32: 31 bytes

Como un fragmento de código GNU C en línea-asm: guarda 2B 1B (solo el retinsn).

Fuente comentada y controlador de prueba en github

La versión de 64 bits se puede llamar directamente desde C con el sistema estándar V x86-64 ABI (usando 2 args ficticios para obtener args en las reglas que quiero). Las convenciones de llamadas personalizadas no son infrecuentes para el código asm, por lo que esta es una característica adicional.

El código de máquina de 32 bits ahorra 1B, porque la fusión de las mitades altas y bajas push16/push16 => pop32solo funciona en modo de 32 bits. Una función de 32 bits necesitaría una convención de llamada personalizada. No deberíamos sostener eso en su contra, pero llamar desde C necesita una función de contenedor.

Después de procesar 4096 ~(ASCII 126) bytes, high = 0x3f040000, low = 0x7e001. Entonces high, el bit más significativo aún no está establecido. Mi código se aprovecha de esto, firmando extendiéndose eaxaedx:eax la cdqcomo una forma de reducir a cero 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 bytes.


Fuente comentada de NASM:

trucos:

  • xchg eax, r32es un byte; más barato que mov. 8086 necesitaba datos en el hacha para muchas más cosas que> = 386, por lo que decidieron gastar mucho espacio de código de operación en el ahora raramente utilizadoxchg ax, r16 .

  • La combinación de push64 y push16 para fusionar alto y bajo en un solo registro guarda las instrucciones de movimiento de datos de registro en dos divsegundos. La versión de 32 bits de este truco funciona aún mejor: push16 / push16 / pop32es solo 5B en total, no 6.

Como presionamos / pop, esto no es seguro para asm en línea en el SysV amd64 ABI (con una zona roja) .

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:

También consideré usar rcx como un índice de matriz, en lugar de tener dos contadores de bucle, pero adler32 (s)! = Adler32 (reverse (s)). Entonces no pudimos usar loop. Contar desde -len hasta cero y usar movzx r32, [rsi+rcx]solo usa demasiados bytes.

Si queremos considerar incrementar el puntero nosotros mismos, el código de 32 bits es probablemente el camino a seguir. Incluso el x32 ABI (punteros de 32 bits) no es suficiente, porque inc esies 2B en amd64, pero 1B en i386. Parece difícil superar xor eax,eax/ lodsb/ loop: 4B en total para que cada elemento a su vez se extienda a cero en eax. inc esi/ /movzx r32, byte [esi] / loopes 5B.

scases otra opción para incrementar un puntero con una instrucción 1B en modo de 64 bits. ( rdi/ en edilugar de rsi, entonces tomaríamos el puntero arg rdi). Sin scasembargo, no podemos usar el resultado del indicador como condición de bucle, porque no queremos mantener eax a cero. Una asignación de registro diferente podría salvar un byte después del ciclo.


int[] entrada

La toma de función completa uint8_t[]es la respuesta "principal", porque es un desafío más interesante. Desembalar int[]es una cosa irracional pedirle a nuestra persona que llama que haga en este idioma, pero ahorra 2B.

Si tomamos nuestra entrada como una matriz desempaquetada de enteros de 32 bits, podemos guardar un byte fácilmente (usar lodsdy reemplazar xor eax,eax / cdqcon solo xor edx,edx).

Podemos guardar otro byte poniendo a cero edx con lodsd/ cdq, y reorganizando el ciclo para que cargue el elemento de terminación 0 antes de salir. (Todavía estamos asumiendo que existe, a pesar de que es una matriz de int, no una cadena)

; 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

También hice una versión no probada que usa scasd(versión 1B de add edi,4) y en add eax, [rdi]lugar de lodsd, pero también es de 30 bytes. Los ahorros de tener un higheax al final del ciclo se compensan con un código más grande en otro lugar. Sin 0embargo, tiene la ventaja de no depender de un elemento de terminación en la entrada, lo que quizás no sea razonable para una matriz desempaquetada donde también se nos da la longitud explícitamente.


Controlador de prueba C ++ 11

Ver el enlace de github. Esta respuesta se estaba volviendo demasiado grande, y el controlador de prueba obtuvo más funciones con un código más grande.

Peter Cordes
fuente
2
Permití enteros en lugar de bytes, principalmente porque muchos idiomas ni siquiera tienen un tipo de byte. Los enteros de 32 bits pueden ser una opción poco natural para el ensamblaje, pero el código de golf se trata de exprimir el último byte mientras se mantiene dentro de las reglas. Si una elección "antinatural" lleva a un recuento de bytes más bajo, diría que lo haga.
Dennis
@ Dennis: Entiendo la necesidad de la regla para algunos idiomas. Desearía que hubiera una forma de que la regla solo te permitiera usar int[]si fuera necesario, o guardar más de 4 bytes de código o algo así. No tengo ningún problema para presentar una solución al adler32(int[])problema, pero siento que el adler32(char[])problema es más interesante, ya que es la verdadera función adler32. Es lo que realmente quiero jugar al golf en asm. (Y me encantaría guardar un byte más de alguna manera, ya que en la vida real asm, 33 bytes = 48 bytes si se usa la siguiente función ALIGN 16). Supongo que seguiré jugando golf ambos.
Peter Cordes
@Dennis: también, ¿necesitamos manejar el caso len = 0? Ahorro 2B usando un do{}while(--len)estilo de bucle en lugar de a while(len--){}.
Peter Cordes
44
Cuando se trata de explicaciones, cuanto más detallado, mejor.
Dennis
3
@cat: No, no me parece doloroso. No pasaría mi tiempo escribiendo respuestas de Stackoverflow a preguntas sobre asm / rendimiento, y actualizando el wiki de la etiqueta x86 si lo hiciera: P Si desea saber por qué el código se ejecuta lento o rápido, debe mirar y comprender el asm. Una vez que hace eso por un tiempo, comienza a ver cuándo el compilador podría haber hecho un código más rápido ... y eventualmente comienza a pensar en cómo el compilador podría compilar el código a medida que lo escribe. La optimización para el tamaño del código en lugar del rendimiento es un cambio interesante a veces.
Peter Cordes
8

MATL , 22 bytes

tsQwYsQsh16W15-\l8Mh*s

La entrada puede ser una matriz de números o la cadena ASCII correspondiente.

Pruébalo en línea!

Explicación

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

En realidad, 36 bytes

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

Pruébalo en línea!

Explicación:

;Σ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
fuente
7

Java, 84 bytes

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 se supone que las soluciones Java siempre son un código compilable completo, avíseme.

Sin golf

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

Tendrá que convertir la entrada Stringa int[]( int[]es un byte más corto que byte[]ochar[] ).

Salida

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
fuente
1
Buena respuesta, y bienvenido al sitio! Además, las soluciones que no están completas y son compilables están bien, a menos que el desafío establezca explícitamente que debería ser un programa completo. Esta es una función completa, por lo que cuenta.
DJMcMayhem
6

Piet, 120 codeles codelsize 1

Con codelsize 20:

codelsize 20

Notas / ¿Cómo funciona?

  • Como no es posible usar una matriz o cadena como entrada, este programa funciona tomando una serie de enteros (que representan caracteres ascii) como entradas. Al principio pensé en usar entradas de caracteres, pero tuve problemas para encontrar una buena solución para la terminación, por lo que ahora termina cuando se ingresa cualquier número menor que 1. Originalmente, solo eran valores negativos para la terminación, pero tuve que cambiar la inicialización después de escribir el programa, por lo que ahora no puedo ajustar lo requerido 2, solo un 1(26/45 en la imagen de seguimiento). Sin embargo, esto no importa porque, según las reglas de desafío, solo se permiten caracteres ascii imprimibles.

  • Luché durante mucho tiempo con la reentrada del bucle, aunque al final encontré una solución bastante elegante. No pointeroswitch operaciones, solo el intérprete choca con las paredes hasta que vuelve a la transición al códec verde para leer la entrada (43-> 44 en las imágenes de seguimiento).

  • La terminación del bucle se logra duplicando primero la entrada, agregando 1 y luego verificando si es mayor que 1. Si es así, se activa el selector de códeles y la ejecución continúa en la ruta inferior. Si no es así, el programa continúa a la izquierda (Codeles amarillos brillantes, 31/50 en las imágenes de rastreo).

  • El tamaño de entrada admitido depende de la implementación del intérprete, aunque sería posible admitir una entrada arbitrariamente grande con el intérprete correcto (por ejemplo, un intérprete de Java que utiliza BigIntegercomo valores internos)

  • Acabo de ver que la configuración incluye una innecesaria DUPy CC(7-> 8-> 9 en las imágenes de seguimiento). No tengo idea de cómo sucedió eso. Sin embargo, esto es efectivamente un noop, alterna el selector de codeles 16 veces, lo que no produce ningún cambio.

Npiet traza imágenes

Configuración y primer bucle:

traza de inicio

Terminación de bucle, salida y salida:

traza final

Salidas

Perdóname si solo incluyo una salida, solo toma mucho tiempo ingresar: ^)

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

Npiet traza para [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
fuente
5

C89, 70 bytes

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

Para probar (compilar 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;
}
orlp
fuente
¿Es así como se zlibve la fuente? Hm ...
gato
1
Esta implementación fue un buen punto de partida para mi versión x86 asm.
Peter Cordes
Puede guardar 1 byte usando en forlugar de while:for(h=0,l=1;*B;)h+=l+=*B++;
ninjalj
5

Laberinto , 37 36 32 31 bytes

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

Pruébalo en línea!

Entrada como una lista de enteros. El programa termina con un error (cuyo mensaje de error va a STDERR).

Explicación

Imprimación de laberinto:

  • Labyrinth tiene dos pilas de enteros de precisión arbitraria, main y aux. (iliary), que inicialmente se rellenan con una cantidad infinita (implícita) de ceros.
  • El código fuente se asemeja a un laberinto, donde el puntero de instrucción (IP) sigue los corredores cuando puede (incluso alrededor de las esquinas). El código comienza en el primer carácter válido en el orden de lectura, es decir, en la esquina superior izquierda en este caso. Cuando la IP llega a cualquier forma de unión (es decir, varias celdas adyacentes además de la que proviene), elegirá una dirección basada en la parte superior de la pila principal. Las reglas básicas son: gire a la izquierda cuando sea negativo, siga adelante cuando sea cero, gire a la derecha cuando sea positivo. Y cuando uno de estos no es posible porque hay un muro, entonces la IP tomará la dirección opuesta. La IP también se da vuelta cuando llega a callejones sin salida.
  • Los dígitos se procesan multiplicando la parte superior de la pila principal por 10 y luego agregando el dígito. Para comenzar un nuevo número, puede presionar un cero con _.

Aunque el código comienza con una "habitación" de 4x2, en realidad son dos bucles separados de dos por dos juntos. La IP simplemente se adhiere a un bucle a la vez debido a los valores de la pila.

Entonces, el código comienza con un bucle 2x2 (en sentido horario) que lee la entrada mientras calcula sumas de prefijos:

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

Ahora tenemos todas las sumas de prefijos en la pila auxiliar , así como una copia de la suma de todos los valores y 0de EOF en main . Con eso, ingresamos otro bucle 2x2 (en el sentido de las agujas del reloj) que suma todas las sumas de prefijos para calcular 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 chimenea principal tiene ahora LOW - 1y HIGHy cero, excepto que no hemos tomado el módulo todavía. El resto del código es completamente lineal:

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.

La IP ahora llega a un callejón sin salida y se da vuelta. Los +y *son esencialmente no-ops, debido a los ceros en la parte inferior de la pila. El 36ahora convierte la parte superior de main en 63, pero los dos {{extraen dos ceros de aux en la parte superior. Luego %intenta dividir por cero, lo que termina el programa.

Tenga en cuenta que Labyrinth usa enteros de precisión arbitraria, por lo que diferir el módulo hasta el final de la suma no causará problemas con el desbordamiento de enteros.

Martin Ender
fuente
5

Python 2, 60 58 bytes

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

Un enfoque bastante sencillo. Este es un programa completo que toma una lista de enteros a través de STDIN, por ejemplo [72, 105, 33].

(Gracias a @xnor por la increíble sugerencia de alias / inicialización)

Sp3000
fuente
2
Puede hacer H=h=65521para inicializar hmientras alias 65521.
xnor
4

J, 30 bytes

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

Esto probablemente podría condensarse más con un tren diferente.

Uso

Aquí x $ ycrea una lista con xcopias 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

Explicación

+/(+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
millas
fuente
4

Octava, 52 50 bytes

Guardado 2 bytes gracias a @LuisMendo

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

Toma una matriz de enteros como entrada.

low se toma del último elemento de high (antes de sumar) en lugar de calcular la suma explícitamente, ahorrando un gran total de ... 1 byte !

Ejecución de muestra en ideone .

cubilete
fuente
@LuisMendo Ooh, me olvidé +B. Supongo que la especificación de entrada dice que puedes tomar enteros, así que tal vez lo haga.
vaso de precipitados
3

CJam, 30 29 bytes

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

Entrada como una lista de enteros.

Pruébalo aquí.

Explicación

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
fuente
3

Perl 6 , 60 bytes

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

Explicación:

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

Prueba:

#! /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
fuente
3

Python 3 (79 bytes)

Basado en la solución 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)

Reemplacé la multiplicación por un turno y eliminé un par de paréntesis.

Como no puedo publicar comentarios, hice una nueva respuesta.

R2D2
fuente
3

Esquema, 195 bytes

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

Si no fuera por todos esos paréntesis ...

Numeri dice reinstalar a Mónica
fuente
3

Haskell, 54 50 bytes

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

Ejemplo de uso: g [69,97,103,108,101,115,32,97,114,101,32,103,114,101,97,116,33]-> 918816254.

scanlincluye el valor inicial (-> 1) en la lista (-> [1,1+b1,1+b1+b2,..]), por lo que sumestá desactivado por 1, que se corrige al anteponer -1a la lista antes de sumar.

Editar: Gracias @xnor por 4 bytes.

nimi
fuente
Parece que uno puede extraer el resumen en m: m=(`mod`65521).sum g x=m(-1:scanl(+)1x)*4^8+m(1:x). Probablemente haya una mejor manera de arreglar las sumas que anteponer.
xnor
3

JavaScript (ES7), 52 50 bytes

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

ES6 toma 51 bytes (reemplace 4 ** 8 con 65536). Si desea una versión de cadena, para 69 bytes:

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

Editar: Guardado 2 bytes gracias a @ user81655.

Neil
fuente
3

Función ARM Thumb-2 que acepta uint8_t[] : 40 bytes (36B para ABI no estándar yint[] )

Características: módulo no diferido, por lo que las entradas de tamaño arbitrario están bien. En realidad no usa la instrucción de división, por lo que no es lenta. (err, al menos no por esa razón: P)

Ahorro por seguir reglas menos estrictas:

  • -2B si no tenemos que guardar registros antes de usarlos.
  • -2B por requerir que la persona que llama desempaquete bytes en una uint32_t[]matriz.

Entonces, el mejor caso es 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 bytes


Notas:

En lugar de log%mal final, lo hacemos if(low>=m) low-=mdentro del bucle. Si lo hacemos bajo antes que alto, sabemos que ninguno de los dos puede exceder 2*m, por lo que el módulo es solo cuestión de restar o no. A cmpy predicado subes solo 6B en modo Thumb2. El idioma estándar para% es 8B en modo Thumb2:

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

La longitud implícita adler(char *) versión de tiene el mismo tamaño de código que la longitud explícitaadler(uint8_t[], uint32_t len) . Podemos establecer banderas para la condición de salida de bucle con una sola instrucción 2B de cualquier manera.

La versión de longitud implícita tiene la ventaja de funcionar correctamente con la cadena vacía, en lugar de intentar repetir 2 ^ 32 veces.


ensamblar / compilar 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

Sin -static, el proceso que se ejecuta bajo qemu-armno encontró su vinculador dinámico. (Y sí, instalo un ARM configuración cruz-devel sólo por esta respuesta, porque pensé que mi idea predicado-restar estaba ordenada.) En AMD64 Ubuntu, instalar gcc-arm-linux-gnueabi, g++-arm-linux-gnueabi. encontrégdb-arm-none-eabi casi no funcionaba la conexión qemu-arm -g port.

Fuente comentada:

// 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.cpptiene los mismos casos de prueba y main()mi respuesta x86-64, pero comienza de esta manera:

#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
fuente
3

Función de código de máquina x86 de 16 bits: 32 bytes usando una convención de llamada personalizada

Args en registros, y no preservar otros registros que no sean bp (y sp).

En el código de 16 bits, devolvemos un valor de 32 bits en el dx:axpar de registros. Esto significa que no tienen que pasar todas las instrucciones fusión highy loweneax . (Esto también ahorraría bytes en código de 32 y 64 bits, pero solo podemos justificar la descarga de este trabajo a la persona que llama en código de 16 bits).

Fuente comentada y controlador de prueba en github (para x86 16, 32 y 64 bits, y 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 bytes

Probado al ensamblar el mismo código para el modo de 32 bits, por lo que puedo llamarlo (con una función de contenedor) desde C compilado con -m32. Para mí, el modo de 16 bits es algo interesante, las llamadas al sistema DOS no lo son. Todas las instrucciones tienen operandos explícitos, excepto loopy lodsb, por lo que el ensamblaje para el modo de 32 bits utiliza prefijos de tamaño de operando. La misma instrucción, codificación diferente. Pero lodsben modo de 32 bits usará[esi] , por lo que esta versión para prueba funciona con punteros de 32 bits (porque no hacemos ningún cálculo de dirección o incremento / comparación de puntero).

No hay desajustes. Mi arnés de prueba imprime un mensaje si hay una falta de coincidencia.

$ 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 registros de 16 bits, no podemos diferir la reducción del módulo hasta después del ciclo. Hay una diferencia interesante entre 16 bits y otros tamaños de operandos: m = 65521(0xFFF1 ) es más de la mitad de 65536. Restar men acarreo mantiene el valor por debajo de 2 * m, incluso si high=0xFFF0 + 0xFFF0. Después del ciclo, una comparación y resta hará el truco, en lugar de undiv .

Se me ocurrió una nueva técnica para reducir el módulo de un registro después de un anuncio que puede producir un carry . En lugar de poner a cero la mitad superior de la entrada div, use setc dlpara crear un dividendo de 32 bits que contenga el resultado de la suma no truncado ( dhya está puesto a cero). (div hace 32b / 16b => división de 16 bits).

setcc(3 bytes) se introdujo con 386. Para ejecutar esto en 286 o anterior, lo mejor que se me ocurre utiliza la instrucción no documentada salc(establecer AL desde carry) . Es un código de operación de un byte sbb al,al, por lo que podríamos usar salc/ neg alantes de hacer el xchg ax, dx(que de todos modos necesitamos). Sin salc, hay una secuencia 4B: sbb dx,dx/ neg dx. No podemos usar 3B sbb dx,dx/ inc dx, porque eso emularía en setnclugar de hacerlo setc.


Intenté usar un tamaño de operando de 32 bits en lugar de manejar carry, pero no son solo las addinstrucciones las que necesitan un prefijo de tamaño de operando. Las instrucciones que configuran las constantes, etc., también necesitan prefijos de tamaño de operando, por lo que no fue el más pequeño.

Peter Cordes
fuente
2

Perl 5, 43 bytes

42 bytes, más 1 para -aE lugar de-e

La entrada es como enteros decimales, separados por espacios.

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

Una punta de mi sombrero para Sp3000 , de quien tomé ideas para esta respuesta.

Cómo funciona:

  1. Debido a -a, $. comienza en 1 y @Fes la matriz de entrada. $hcomienza en 0. $_es utilizado pormap como un marcador de posición para cada elemento de una matriz.
  2. map$h+=$.+=$_,@Fsignifica que para cada elemento en @Fque agregamos ese elemento $.y luego agregamos $.a$h .
  3. Luego hacemos la aritmética modular $.%65521+$h%65521*4**8(es decir, ($. % 65521) + ( ($h % 65521) * (4**8) )y say(imprimimos) el resultado.
msh210
fuente
1

Factor, 112 109 103 bytes

Ahora , esta es una traducción literal del algoritmo en la pregunta ... ahora que realmente lo hice, ya sabes, correcto.

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

Sin golf:

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

Espera cualquier secuencia de números o una cadena (no hay mucha diferencia, aunque técnicamente no son lo mismo).

No sé cómo funcionará esto para el límite dado en una versión de Factor compilada con un tamaño de palabra de 32 bits, pero en mi máquina de 6 GB y 64 bits 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
gato
fuente
1

Ruby, 91 bytes

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

Clojure, 109 bytes

Basado en la solución de @Mark Adler .

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

Sin golf

(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
millas
fuente
1

Javascript (130 caracteres golfizados)

Sin golf

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

Pegue en la consola de desarrolladores y luego dele una matriz de bytes EG:

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

Y devolverá la suma de comprobación a la consola

Shubshub
fuente
1

TMP, 55 bytes

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

La implementación en Lua se puede encontrar aquí: http://preview.ccode.gq/projects/TMP.lua

brianush1
fuente
1
¡Bienvenido a Programming Puzzles y Code Golf! ¿Este lenguaje satisface nuestra definición de lenguajes de programación ?
gato
@cat Creo que sí, pero no estoy seguro de si realmente admite "tuplas".
brianush1
BrainFuck tampoco, así que probablemente estés bien. Si está completo, puede encontrar números primos y puede hacer las cosas básicas que cualquier otro lenguaje puede hacer (y puede), funcionará :) CSS no es un lenguaje de programación en sí mismo y tampoco lo es HTML, sino CSS3 + HTML está completo y puede encontrar números primos.
gato
Entonces, ¿está bien usarlo en CodeGolf?
brianush1
Creo que sí, no conozco ni a TMP ni a Lua, por lo que una explicación de este código sería de gran ayuda (y sería una excelente respuesta). : D
gato
1

Python 3.5, 82 bytes:

( -1 byte gracias a Neil ! )

( -1 byte gracias a Mathmandan ! )

( -4 bytes gracias a Dennis ! )

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

Una lambdafunción anónima . Acepta una matriz de bytes, aplica todo el algoritmo a la matriz y genera el resultado. Ha trabajado con éxito para todos los casos de prueba. Llama a esto asignándole una variable y luego llamando a esa variable como llamaría a una función normal. Si está utilizando el shell, esto debería salir sin una función de impresión. Sin embargo, si no lo está, debe ajustar la llamada a la print()función en la función para ver realmente la salida.

Pruébalo en línea! (Ideone)

R. Kap
fuente
(E+15)es en realidad un byte más largo que 65536.
Neil
@Neil Gracias por el consejo. Ya está arreglado.
R. Kap
@ Sp3000 Entonces? Sería importa si se agregaron algunos bytes, pero el hecho de que añaden ningún bytes restos bien conmigo.
R. Kap
4**8es un byte más corto que 65536.
Mathmandan
Puede guardar 4 bytes colocando los corchetes alrededor del generador e iterando de 0 a len (w) . Se pueden guardar otros 6 bytes explotando la precedencia del operador.
Dennis
1

Fisión , 324 bytes

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

Advertencia justa, la única implementación en la que he probado esto es mi propio puerto del lenguaje a F #. No es golf, principalmente porque me pareció más fácil tener un par de carreras largas mientras mi constante principal se enfriaba en la parte inferior, por lo que puedo volver y ajustarla.

¿Como funciona?

  • El R'~++Y++~'Lbloque fusiona una constante de 256 y lo lanza hacia abajo, configurando el multiplicador de masa del reactor directamente debajo de él.
  • El R'~++A++~'Abloque fusiona otros 256 y lo lanza hacia el reactor de arriba, que fisiona la partícula en dos múltiplos de masa de65536 masa cada uno, lanzándolos hacia la izquierda y hacia la derecha (donde la partícula derecha es destruida inmediatamente por el terminador).
  • La partícula izquierda golpea otro reactor y se somete a fisión, dividiéndose en dos partículas de igual masa que se dirigen hacia arriba y hacia abajo.
  • La potencia de dos partículas que viaja hacia arriba pasa a través de una manipulación de masa neta cero, se refleja a la izquierda y luego establece el multiplicador de masa del reactor de fusión. Este reactor será cómo multiplicamos el bloque H.
  • La partícula que viaja hacia abajo se refleja a la izquierda y arroja masa a largo plazo, alcanzando finalmente una masa de 65521(nuestro gran cebado).
  • El espejo giratorio (Z ) al final de la ejecución hace que la partícula duplique el cebado, enviando uno de vuelta a la derecha donde finalmente establece la masa almacenada del reactor de fisión ( ^). Así es como aplicaremos el operador de módulo al bloque H.
  • La segunda copia se refleja hacia atrás, donde realiza una función análoga para el reactor de fisión (< ) que usaremos para el bloque L.
  • Ahora que nuestras constantes están en su lugar, nos involucramos en travesuras en la esquina superior izquierda para leer nuestra entrada y generar nuestras dos listas. Para ser honesto, olvido cómo funcionan, pero para la cadena vacía tuve que reducir la velocidad de la partícula sumadora del bloque H, lo que explica la|S "torre de enfriamiento".
  • \Y/ fusiona el bloque L (que entra por el canal izquierdo) y el bloque H (que entra por el canal derecho), luego los golpea en un terminador que establece el código de salida en la masa fusionada.
Andrew Coonce
fuente
A menos que esté cometiendo un error en alguna parte, esto no parece funcionar con el intérprete oficial ( enlace ). ¿Dónde podría obtener su puerto a F #?
Dennis
@ Dennis Estoy tratando de averiguar si el error está de mi lado o no, pero tampoco puedo hacer que el intérprete funcione. Veré si puedo hacerlo funcionar y luego actualizaré mi respuesta si es necesario.
Andrew Coonce
@ Dennis Parece que el intérprete en línea no maneja abortos de código de error *, que es como estoy devolviendo la salida. Veré si puedo encontrar otro intérprete para verificar la salida mañana.
Andrew Coonce