Обчисліть контрольну суму Adler-32


32

Фон

Adler-32 - це 32-бітна контрольна сума, винайдена Марком Адлером у 1995 році, яка є частиною широко використовуваної бібліотеки zlib (також розробленої Adler). Adler-32 не настільки надійний, як 32-бітна циклічна перевірка надмірності , але - принаймні, в програмному забезпеченні - це набагато швидше і простіше втілити в життя.

Визначення

Нехай B = [b 1 , ⋯, b n ] - масив байтів.

Контрольна сума B Adler-32 визначається як результат низької + 65536 × висоти , де:

  • низький: = ((1 + b 1 + ⋯ + b n ) mod 65521)

  • високий: = (((1 + b 1 ) + (1 + b 1 + b 2 ) + ⋯ (1 + b 1 + ⋯ + b n )) mod 65521)

Завдання

Давши байтовий масив як вхід, обчислити та повернути контрольну суму Adler-32, дотримуючись наступного.

  • Ви можете приймати вхід як масив байтів або цілих чисел, або як рядок.

    В обох випадках у вході будуть знаходитися лише байти, відповідні друкованим символам ASCII.

    Можна припустити, що довжина вводу буде задовольняти 0 <довжина ≤ 4096 .

  • Якщо ви вирішили надрукувати вихід, ви можете використовувати будь-яку позитивну базу до 256.

    Якщо ви вибрали одинаковий режим, переконайтесь, що інтерпретатор може обробляти до 2 32 - 983056 байт виводу на машині з 16 ГБ оперативної пам’яті.

  • Вбудовані модулі, які обчислюють контрольну суму Adler-32, заборонені.

  • Діють стандартні правила .

Тестові справи

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

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

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

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

7
Зауважу, що багато відповідей тут зазнають невдач із великими або дуже великими послідовностями введення, коли вони переповнюють 32 або 64-бітні цілочисельні суми, через відстрочку операції по модулю до обчислення сум. Справді сумісна реалізація повинна буде робити модульну операцію хоча б періодично, щоб уникнути переповнення сум. 32-бітове підписане ціле число переповниться лише після 4096 0xff. 64-бітове підписане ціле число переповниться після 256 Мб 0xff.
Марк Адлер

@MarkAdler Хм, справедлива точка. Оскільки я не вказував, що рішення повинні працювати для довільно довгих рядків, і я не хочу визнати недійсними існуючі відповіді, я встановлю обмеження для довжини введення.
Денніс

@MarkAdler Я не думаю, що це має значення. Я цілком впевнений, що переповнення (підписані 32-бітні цілі числа) може відбуватися лише з 4104 або більше байтами введення, оскільки максимальне значення високого до модуля дорівнює n * (n + 1) / 2 * 255 + n . Крім цього, виклик обмежує введення в байтах, що відповідають друкованим символам ASCII.
Денніс

Ми також можемо дозволити мовам переповнювати їх числові типи і вимагати лише, щоб повернутий результат був еквівалентним, враховуючи переповнення, правильному результату.
миль

1
@PeterCordes Так, масиви 32-бітних ints ідеально чудові. Принаймні, на мій погляд, матеріали повинні зосереджуватись на алгоритмі гольфу та приділяти якомога менше уваги вводу-виводу.
Денніс

Відповіді:


3

Желе, 19 17 байт

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

Спробуйте в Інтернеті!

+\,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

Ще краще:⁹²¤
Деніс

1
@Dennis Я тоді перевершив ваш 18-байт.
Leaky Nun

1
Ну, ви перемогли ..
Leaky Nun

64

Математика, 46 байт

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

Анонімна функція, яка займає цілий масив і повертає Adler-32, з деякими поліпшеннями від миль та Мартіна (див. Коментарі).

миль 'також 46 байт , але швидше:

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

37
... Ви просто гольфували свій відомий алгоритм?
Mego

25
Пробач, якщо мене трохи вразило зірка. Не щодня ви бачите таке гучне ім'я в розробці програмного забезпечення на нашому скромному маленькому сайті. Ласкаво просимо на борт!
Mego

6
Не все таке велике.
Марк Адлер

3
Якщо ви маєте на увазі мене, це перший раз, коли я думав реалізувати Adler-32 в Mathematica.
Марк Адлер

9
Або, можливо, ви готовили це рішення, коли ви приєдналися до Code Golf, просто чекаючи, коли його попросять. "Нарешті!" ;-)
Антті Хаапала

13

Юлія, 73 46 байт

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

Це анонімна функція, яка приймає масив і повертає ціле число. Щоб викликати його, призначте його змінній.

Ми поєднуємо sum(x) + 1і sum(cumsum(x) + 1)в масив, де xє вхідний масив, і беремо кожен модуль 65521. Потім ми обчислюємо крапковий добуток 1 і 4 8 , що дає нам (sum(x) + 1) + 4^8 * sum(cumsum(x) + 1), що саме є формулою Адлера-32.

Спробуйте в Інтернеті! (Включає всі тестові випадки)

Збережено 27 байт завдяки Sp3000 та Dennis!


Ого, це справді розумно.
кіт

@cat У мене є Sp3000 і Денніс, щоб подякувати за більшість кмітливості. :)
Олексій А.

11

Функція машинного коду x86-64: 33 32 байти (або 31 30 байт із int[]входом замість char[])

Функція машинного коду x86-32: 31 байт

Як фрагмент коду GNU C inline-asm: зберігає 2B 1B (лише retінсн).

Прокоментував джерело та тестовий драйвер на github

64-бітну версію можна дзвонити безпосередньо з C зі стандартною системою V x86-64 ABI (використовуючи 2 манекени, щоб отримати аргументи в потрібні регістри). Спеціальні умови викликів не є рідкістю для коду asm, тому це бонусна функція.

32-бітний машинний код економить 1B, оскільки об'єднання високої та нижньої половини push16/push16 => pop32працює лише в 32-бітовому режимі. Для 32-бітної функції потрібна спеціальна конвенція про дзвінки. Ми не повинні проти цього протистояти, але для виклику з C потрібна функція обгортки.

Після обробки 4096 ~(ASCII 126) байт, high = 0x3f040000, low = 0x7e001. Отже high, найбільш значущий біт ще не встановлений. Мій код використовує це, знак подовжувачів eaxв edx:eaxс cdqяк спосіб обнулення 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 байти.


Прокоментував джерело NASM:

хитрощі:

  • xchg eax, r32- один байт; дешевше, ніж мов. 8086 знадобилося даних у ax для набагато більше матеріалів, ніж> = 386, тож вони вирішили витратити багато простору коду для тепер уже рідко використовуваних xchg ax, r16.

  • Змішування push64 і push16 для об'єднання високих і низьких в єдиний регістр зберігає інструкції щодо переміщення даних reg-reg протягом двох divс. 32-бітна версія цього трюку працює ще краще: push16 / push16 / pop32всього 5B, а не 6.

Оскільки ми натискаємо / стикаємо, це не безпечно для вбудованого ASM в SysV amd64 ABI (з червоною зоною) .

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:

Я також розглядав можливість використання rcxв якості індексу масиву, замість того, щоб мати два лічильника циклу, але adler32 (s)! = Adler32 (reverse (s)). Тому ми не могли використати loop. Підрахунок від -len до нуля та movzx r32, [rsi+rcx]просто використовує занадто багато байтів.

Якщо ми хочемо розглянути можливість збільшення покажчика самостійно, 32-бітовий код - це, мабуть, шлях. Навіть x32 ABI (32-бітових покажчиків) недостатньо, тому що inc esiце 2B на amd64, а 1B на i386. Здавалося, важко перемогти xor eax,eax/ lodsb/ loop: 4B всього, щоб отримати кожен елемент у свою чергу, нульовий-розширений в eax. inc esi// movzx r32, byte [esi]/ loop5B.

scasє ще одним варіантом збільшення покажчика з 1B інструкцією в 64-бітовому режимі. ( rdi/ ediзамість цього rsi, ми б взяли аргумент вказівника rdi). scasОднак ми не можемо використовувати результат прапора як умову циклу, тому що ми не хочемо, щоб eax було нульовим. Різне розподілення реєстру може, можливо, зберегти байт після циклу.


int[] вхід

Повна функція uint8_t[]- це "головна" відповідь, оскільки це цікавіше завдання. Розпаковувати до int[]- це нерозумно, щоб попросити нашого абонента зробити цією мовою, але це заощадить 2B.

Якщо ми сприймаємо наші дані як розпакований масив із 32-бітових цілих чисел, ми можемо легко зберегти один байт (використовувати lodsdта замінити xor eax,eax / cdqпросто xor edx,edx).

Ми можемо зберегти інший байт, занулюючи edx за допомогою lodsd/ cdq, і переставляючи цикл, щоб він завантажував завершуючий 0 елемент перед виходом. (Ми все ще припускаємо, що він існує, навіть якщо це масив int, а не рядок).

; 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

Я також зробив неперевірену версію, яка використовує scasd(1B версія add edi,4) і add eax, [rdi]замість lodsd, але це також 30 байт. Економія від наявності highв eax в кінці циклу врівноважується більшим кодом в іншому місці. Це має перевагу в тому, що він не залежить від 0елемента, що закінчується на вході, але це може бути невиправданим для розпакованого масиву, де нам також явно задана довжина.


C ++ 11 тестовий драйвер

Дивіться посилання github. Ця відповідь стала надто великою, і тестовий драйвер отримав більше функцій з більшим кодом.


2
Я дозволяв цілі числа замість байтів, головним чином тому, що багато мов навіть не мають байтового типу. 32-бітні цілі числа можуть бути неприродним вибором для складання, але кодовий гольф - це витіснення останнього байту, залишаючись за правилами. Якщо "неприродний" вибір призводить до меншої кількості байтів, я б сказав, піти на це.
Денніс

@Dennis: Я розумію необхідність правила для деяких мов. Я хотів би, щоб правило було дозволити вам використовувати лише те, int[]якщо це було необхідно, або зберегло більше 4-х байт коду чи щось. Я не маю жодних проблем із представленням рішення adler32(int[])проблеми, але я вважаю, що adler32(char[])проблема є цікавішою, оскільки це реальна функція adler32. Це те, що мені дуже хочеться грати в гольф. (Я дуже хотів би якось зберегти ще один байт, оскільки в реальному житті asm 33 байти = 48 байт, якщо використовується наступна функція ALIGN 16). Я думаю, що я продовжуватиму займатися гольфом обох.
Пітер Кордес

@Dennis: також, чи потрібно нам обробляти випадок len = 0? Я зберігаю 2B, використовуючи do{}while(--len)стиль циклу замість a while(len--){}.
Пітер Кордес

4
Що стосується пояснень, то чим детальніше, тим краще.
Денніс

3
@cat: Ні, я не вважаю асм болючим. Я б не витрачав свій час на написання відповідей Stackoverflow на запитання asm / performance та оновлення wiki тегів x86, якщо б це зробити: P Якщо ви хочете знати, чому код працює повільно чи швидко, вам потрібно подивитися і зрозуміти ASM. Як тільки ви це зробите деякий час, ви починаєте бачити, коли компілятор міг би зробити швидший код ... і врешті-решт починаєте думати про те, як компілятор міг би скласти код під час його написання. Оптимізація розміру коду замість продуктивності іноді є цікавою зміною.
Пітер Кордес

8

MATL , 22 байти

tsQwYsQsh16W15-\l8Mh*s

Введенням може бути масив чисел або відповідний рядок ASCII.

Спробуйте в Інтернеті!

Пояснення

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

7

Власне, 36 байт

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

Спробуйте в Інтернеті!

Пояснення:

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

7

Java, 84 байти

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

Якщо рішення Java завжди мають бути повним компільованим кодом, будь ласка, дайте мені знати.

Безумовно

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

Примітка

Ви повинні перетворити вхід Stringв int[]( int[]один байт коротше byte[]або char[]).

Вихідні дані

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

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

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

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

1
Приємна відповідь і ласкаво просимо на сайт! Крім того, рішення, яке не є повним та компілюючим, чудово, якщо в виклику прямо не зазначено, що це має бути повноцінна програма. Це повноцінна функція, тому вона рахується.
DJMcMayhem

6

Піт, 120 коделів кодування 1

З коделі розміром 20:

коделі розміру 20

Примітки / Як це працює?

  • Оскільки неможливо використовувати масив або рядок в якості вхідних даних, ця програма працює, приймаючи ряд цілих чисел (представляючи символи ascii) як вхідні дані. Спочатку я думав про використання символьних введень, але намагався знайти приємне рішення для припинення, тому тепер він припиняється, коли вводиться будь-яке число менше 1. Спочатку це були лише негативні значення для припинення, але мені довелося змінити ініціалізацію після написання програми, тому тепер я не можу відповідати необхідному 2, лише 1(26/45 на зображенні сліду). Це не має значення, тому що згідно з правилами виклику, дозволені лише друковані символи ascii.

  • Довго боровся з повторним введенням циклу, хоча в підсумку я знайшов досить елегантне рішення. Ні, pointerабо switchоперації, лише інтерпретатор працює в стіни, поки він не перейде назад у зелений кодекс, щоб прочитати вхідні дані (43-> 44 на зображеннях слідів).

  • Закінчення циклу досягається спочатку дублюючи вхід, додаючи 1, а потім перевіряючи, чи він більший за 1. Якщо він є, спрацьовує вибір кодера, і виконання продовжується на нижньому шляху. Якщо ні, програма продовжує ліворуч (яскраві жовті коделі, 31/50 на зображеннях слідів).

  • Підтримуваний розмір вводу залежить від реалізації інтерпретатора, хоча можна було б підтримати довільно великий вхід правильним інтерпретатором (Скажімо, наприклад, інтерпретатор Java, який використовує BigIntegerяк внутрішні значення)

  • Щойно побачив, що налаштування включає одне непотрібне DUPі CC(7-> 8-> 9 у зображеннях слідів). Не знаю, як це сталося. Це фактично noop, однак він перемикає вибір кодера 16 разів, що не призводить до змін.

Зображення слідів Npiet

Налаштування та перший цикл:

стартовий слід

Закінчення, вихід та вихід циклу:

закінчення

Виходи

Пробачте, якщо я включаю лише один вихід, для введення потрібно просто тривалий час: ^)

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

Ніпеєвий слід для [65, -1]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5

C89, 70 байт

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

Для тестування (компіляції з 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;
}

Так zlibвиглядає джерело? Гм ...
кіт

1
Ця реалізація стала хорошим початковим моментом для моєї версії x86 asm.
Пітер Кордес

Можна зберегти 1 байт, використовуючи forзамість while:for(h=0,l=1;*B;)h+=l+=*B++;
ninjalj

5

Лабіринт , 37 36 32 31 байт

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

Спробуйте в Інтернеті!

Введіть як список цілих чисел. Програма закінчується помилкою (повідомлення про помилку переходить до STDERR).

Пояснення

Лабіринтний праймер:

  • Лабіринт має два штабеля довільної точності цілих чисел, основний і AUX (iliary), які спочатку заповнені (неявне) нескінченну кількість нулів.
  • Вихідний код нагадує лабіринт, де вказівник інструкції (IP) слідує за коридорами, коли може (навіть за кутами). Код починається з першого дійсного символу в порядку читання, тобто у верхньому лівому куті в цьому випадку. Коли IP доходить до будь-якої форми з'єднання (тобто декількох суміжних комірок на додаток до тієї, з якої він увійшов), він вибере напрямок на основі верхньої частини основного стеку. Основні правила: поверніть ліворуч при негативі, продовжуйте рухатись вперед, коли нуль, поверніть праворуч, коли позитивно. І коли одне з них неможливо, тому що є стіна, то IP буде приймати протилежний бік. ІС також обертається, коли потрапляє в тупики.
  • Цифри обробляються шляхом множення верхньої частини основного стека на 10, а потім додавання цифри. Щоб почати нове число, можна натиснути нуль за допомогою _.

Хоча код починається з "кімнати" 4х2, це насправді дві окремі петлі, дві на дві. ІЗ просто трапляється одночасно в одному циклі через значення стека.

Таким чином, код починається з циклу 2x2 (за годинниковою стрілкою), який зчитує введення під час обчислення суми префікса:

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

Тепер у нас є всі префіксні суми на стеку aux , а також копія суми за всіма значеннями та 0від EOF в основному . З цим ми вводимо ще один цикл 2x2 (за годинниковою стрілкою), який підсумовує всі суми префікса для обчислення 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.

Основний стек зараз має LOW - 1і HIGHнуль, за винятком того, що ми ще не взяли модуль. Залишок коду повністю лінійний:

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.

IP зараз потрапляє в глухий кут і обертається. +І *практично відсутні-OPS, з нулів в нижній частині стека. 36Тепер виявляється у верхній частині основного INTO 63, але два {{тягнути два нуля з Окса на вершині. Потім %намагається ділити на нуль, що завершує програму.

Зауважте, що Лабіринт використовує цілі числа з довільною точністю, тому відкладання модуля до кінця суми не спричинить проблем із цілим переповненням.


5

Python 2, 60 58 байт

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

Досить прямолінійний підхід. Це повна програма, яка бере список цілих чисел через STDIN, наприклад [72, 105, 33].

(Дякуємо @xnor за дивовижну підказку згладжування / ініціалізації)


2
Ви можете зробити H=h=65521ініціалізацію hпід час отримання псевдоніму 65521.
xnor

4

J, 30 байт

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

Це, мабуть, могло б бути скорочене ще одним поїздом.

Використання

Тут x $ yстворюється список із xкопіями 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

Пояснення

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

4

Октава, 52 50 байт

Збережено 2 байти завдяки @LuisMendo

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

Приймає масив цілих чисел як вхідний.

низький береться з останнього елемента високого (перед підбиттям підсумків), а не чітко обчислює суму, заощаджуючи загальну суму ... 1 байт !

Зразок запущений на ideone .


@LuisMendo О, я забув про це +B. Я думаю, що вхідні характеристики говорять, що ви можете взяти цілі числа, тому, можливо, я просто це зроблю.
мензурка

3

CJam, 30 29 байт

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

Введіть як список цілих чисел.

Перевірте це тут.

Пояснення

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

3

Perl 6 , 60 байт

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

Пояснення:

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

Тест:

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

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

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

plan +@tests;

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

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

3

Python 3 (79 байт)

На основі рішення Р. Капа.

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

Я замінив множення на зсув і зняв пару дужок.

Оскільки я не можу публікувати коментарі, я зробив нову відповідь.



3

Haskell, 54 50 байт

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

Приклад використання: g [69,97,103,108,101,115,32,97,114,101,32,103,114,101,97,116,33]-> 918816254.

scanlвключає в себе початкове значення (-> 1) у списку (-> [1,1+b1,1+b1+b2,..]), тому значення sumoff вимикається 1, яке фіксується попередньою -1до списку перед підсумовуванням.

Редагувати: Дякую @xnor за 4 байти.


Схоже , що ви можете отримати з підсумкових в m: m=(`mod`65521).sum g x=m(-1:scanl(+)1x)*4^8+m(1:x). Напевно, є кращий спосіб зафіксувати суми, ніж попередня оплата.
xnor

3

JavaScript (ES7), 52 50 байт

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

ES6 займає 51 байт (замініть 4 ** 8 на 65536). Якщо ви хочете версію рядка, то для 69 байт:

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

Редагувати: збережено 2 байти завдяки @ user81655.


3

Функція ARM Thumb-2 приймає uint8_t[]: 40 байт (36B для нестандартних ABI і int[])

Особливості: не відкладений модуль, тому введення довільного розміру є нормальним. Насправді не використовується інструкція поділу, тому це не повільно. (помилка, принаймні, не з цієї причини: P)

Економія від дотримання менш суворих правил:

  • -2B, якщо нам не доведеться зберігати регістри перед їх використанням.
  • -2B для того, щоб абонент вимагав розпаковувати байти в a uint32_t[] масив.

Отже, найкращий варіант - 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 байт


Примітки:

Замість log%mкінця робимо if(low>=m) low-=mвсередині циклу. Якщо ми робимо низько перед високим, ми знаємо, що жодне з них не може перевищити 2*m, тому модуль - це лише питання віднімання чи ні. А cmpі subпрогнозованим є лише 6B в режимі Thumb2. Стандартна ідіома для% 8B в режимі Thumb2:

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

Версія неявної довжини adler(char *)має той самий розмір коду, що і явна довжинаadler(uint8_t[], uint32_t len) . Ми можемо встановити прапори для умови виходу з циклу за допомогою однієї інструкції 2B в будь-якому випадку.

Версія неявної довжини має перевагу правильно працювати з порожнім рядком, а не намагатися циклічно 2 ^ 32 рази.


збирати / компілювати з:

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

або

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

Без -staticцього процес, що працює під цим qemu-arm, не знайшов динамічного лінкера. (І так, я встановити ARM крос-Devel настройки тільки для цієї відповіді, тому що я думав , що моя ґрунтується-віднімати ідея була акуратною.) На amd64 Ubuntu, встановити gcc-arm-linux-gnueabi, g++-arm-linux-gnueabi. Я виявив gdb-arm-none-eabi, що ледве працював підключення до qemu-arm -g port.

Коментоване джерело:

// 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.cppмає ті ж тестові випадки, що і main()для моєї відповіді x86-64, але починається так:

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

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

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


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


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

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

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

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

3

x86 16-бітова функція машинного коду: 32 байти за допомогою спеціального режиму викликів

Аргументи в регістрах і не зберігають регістри, крім bp (і sp).

У 16-бітовому коді ми повертаємо 32-бітове значення в dx:axпарі регістру. Це означає , що ми не повинні витрачати якісь - або інструкції злиття highі lowв eax. (Це також збереже байти в 32 та 64 бітовому коді, але ми можемо виправдати лише завантаження цієї роботи на абонент у 16-бітовому коді.)

Прокоментував джерело та тестовий драйвер на github (для x86 16, 32 та 64 біт та 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 байти

Перевірено шляхом складання одного і того ж коду для 32-бітового режиму, тому я можу викликати його (з функцією обгортки) від C, складеного з -m32. Для мене 16-ти бітний режим дещо цікавий, системні дзвінки DOS - ні. Усі інструкції мають явні операнди, за винятком loopі lodsb, тому для складання в 32-бітовому режимі використовуються префікси розміру операнду. Та сама інструкція, різне кодування. Але lodsbв 32-бітовому режимі буде використовувати[esi] , тому ця версія для тестування працює з 32-бітовими вказівниками (оскільки ми не робимо жодного збільшення чи порівняння математичної адреси чи покажчика).

Невідповідностей Мій тестовий джгут роздруковує повідомлення, якщо є невідповідність.

$ 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

За допомогою 16-бітних регістрів ми не можемо відкласти скорочення модуля до закінчення циклу. Існує цікава різниця між 16-бітовими та іншими розмірами операндів: m = 65521( 0xFFF1) більше половини 65536. Віднімання mна переносі зберігає значення нижче 2 * м, навіть якщо high=0xFFF0 + 0xFFF0. Після циклу порівняння та віднімання зробить фокус замість аdiv .

Я придумав нову техніку для зменшення модуля регістра після додавання, який може спричинити перенесення . Замість нуль верхньої половини введення для div, використовуйте setc dlдля створення 32-бітового дивіденду, утримуючи несечений результат додавання ( dhвже нульовий). ( divчи 32b / 16b => 16-бітний поділ.)

setcc(3 байти) було введено з 386. Щоб запустити це на 286 або раніше, найкраще, що я придумав, використовує недокументовану salcінструкцію (встановіть AL from carry) . Це однобайтовий опкод для sbb al,al, тому ми могли використовувати salc/ neg alперед тим, як робити xchg ax, dx(що нам все одно потрібно). Без salcцього є 4B послідовність: sbb dx,dx/ neg dx. Ми не можемо використовувати 3B sbb dx,dx/ inc dx, тому що це наслідує, setncа не setc.


Я спробував використовувати 32-бітний розмір операнду, а не обробляти перенос, але це не лише addінструкції, які потребують префікса розміру операнду. Інструкції зі встановлення констант тощо потрібні також префікси розміру операнду, щоб вони не були найменшими.



2

Perl 5, 43 байти

42 байти, плюс 1 для -aEзамість-e

Введіть як десяткові цілі числа, розділені пробілом.

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

Наконечник мого капелюха Sp3000 , від якого я взяв ідеї для цієї відповіді.

Як це працює:

  1. Через -a, $. починається з 1 і @Fє вхідним масивом. $hпочинається з 0. $_використовується mapяк заповнювач для кожного елемента масиву.
  2. map$h+=$.+=$_,@Fозначає, що для кожного елемента в @Fми додаємо цей елемент, $.а потім додаємо $.до $h.
  3. Потім робимо модульну арифметику $.%65521+$h%65521*4**8(тобто ($. % 65521) + ( ($h % 65521) * (4**8) )і say(друкуємо) результат.

1

Фактор, 112 109 103 байт

Тепер це буквальний переклад алгоритму в питанні ... тепер, коли я його фактично зробив, знаєте, правильно.

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

Безголовки:

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

Очікує будь-якої послідовності чисел або рядка (різниця не велика, хоча технічно вони не однакові).

Я не знаю, як це буде реалізовуватися за вказаний ліміт для версії Factor, складеної з 32-розрядним розміром слова, але на моєму 6 Гб 64-бітній машині 2,2 ГГц:

IN: scratchpad 1040 63 <array>

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

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

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


1

Clojure, 109 байт

На основі @Mark Адлера розчину .

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

Безумовно

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

Використання

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

1

Javascript (130 персонажів у гольф)

Безумовно

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

Гольф

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

Вставте в консоль розробників і надайте їй масив байтів EG:

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

І поверне контрольну суму на консоль


1

TMP, 55 байт

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

Реалізацію в Луї можна знайти тут: http://preview.ccode.gq/projects/TMP.lua


1
Ласкаво просимо до головоломки програмування та коду для гольфу! Чи відповідає ця мова нашому визначенню мов програмування ?
кіт

@cat Я вважаю, що це так, але я не впевнений, чи дійсно він підтримує "кортежі?"
brianush1

Ні BrainFuck, так що ви, мабуть, добре. Якщо він завершений, може знаходити прості номери та виконувати основні речі, якими може займатися будь-яка інша мова (і може), це працюватиме :) CSS не є мовою програмування самостійно, і це не HTML, а CSS3 + HTML є повним твердженням і може знайти праймери.
кіт

Отже, це нормально використовувати в CodeGolf?
brianush1

Я думаю, що так - я не знаю ні TMP, ні Lua, тому пояснення цього коду було б чудовою підмогою (і зробило б це чудовою відповіддю). : D
кіт

1

Python 3,5, 82 байти:

( -1 байт завдяки Нілу ! )

( -1 байт завдяки математиці ! )

( -4 байти завдяки Деннісу ! )

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

Анонімна lambdaфункція. Приймає байтовий масив, застосовує до масиву весь алгоритм і видає результат. Успішно працював у всіх тестових випадках. Ви називаєте це, призначаючи йому змінну, а потім викликаєте цю змінну так, як ви б називали звичайну функцію. Якщо ви використовуєте оболонку, то це має виводитися без функції друку. Однак, якщо ви цього не зробите, то ви повинні загорнути виклик функції у print()функцію, щоб фактично побачити вихід.

Спробуйте в Інтернеті! (Ідеон)


(E+15)насправді байт довше, ніж 65536.
Ніл

@Neil Дякую за пораду. Це зараз виправлено.
Р. Кап

@ Sp3000 Отже? Було б важливо, якби вони додали кілька байтів, але те, що вони не додають байтів, добре відповідає мені.
Р. Кап

4**8- байт коротший, ніж 65536.
Матмандан

Ви можете зберегти 4 байти, опустивши дужки навколо генератора і повторивши від 0 до len (w) . Ще 6 байт можна зберегти, використовуючи пріоритет оператора.
Денніс

1

Розділення , 324 байти

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

Справедливе попередження, єдиною реалізацією, на якій я це перевірив, є мій власний порт мови на F #. Це не гольф, головним чином тому, що мені було легше пройти пару тривалих пробіжок, поки мій основний констант охолоджується по дну, тому я можу повернутися і налаштувати його.

Як це працює?

  • R'~++Y++~'LБлок запобіжників 256 константу і запускає його вниз, встановивши масовий множник реактора безпосередньо під ним.
  • R'~++A++~'AБлок запобіжників ще 256 і запускає його вгору в напрямку вище реактора, який поділів частки в двох масових кратних65536 масу кожного, запуск їх вліво і вправо (де права частка негайно знищена термінатором).
  • Ліва частинка потрапляє в інший реактор і зазнає поділу, розщеплюючись на дві частинки однакової маси, спрямовуючись вгору і вниз.
  • Частка потужності, що рухається вгору від двох частинок, проходить через маніпуляцію масою нетто-нуля, відображається зліва, а потім встановлює масовий множник плавкого реактора. Цей реактор буде таким чином, як ми множимо H-блок.
  • Частина, що рухається вниз, відбивається ліворуч і проливає масу з часом, в кінцевому рахунку досягаючи маси 65521 (наш великий прайм).
  • Обертове дзеркало ( Z) в кінці пробігу призводить до того, що частинка дублює праймер, відсилаючи одну назад праворуч, де в кінцевому підсумку встановлюється збережена маса реактора поділу (^ ). Ось так ми застосуємо оператор модуля до блоку H.
  • Друга копія відображається назад, де вона виконує аналогічну функцію для реактора поділу ( <), який ми будемо використовувати для блоку L.
  • Тепер, коли наші константи є на місці, ми беремо участь у шенагіганах у верхньому лівому куті, щоб прочитати наші дані та створити два наші списки. Якщо чесно, я забуваю, як вони працюють, але для порожнього рядка мені довелося уповільнити частинку підсумовування блоку H, що пояснює |S"охолоджувальну вежу".
  • \Y/ зливає L-блок (який надходить через лівий канал) та блок H (який надходить через правий канал), а потім забиває їх у термінатор, який встановлює вихідний код на злиту масу.

Якщо я десь не помиляюся, це, здається, не працює з офіційним перекладачем ( посилання ). Де я міг взяти ваш порт до F #?
Денніс

@Dennis Я намагаюся з’ясувати, чи помилка закінчується чи ні, але я також не можу змусити перекладача працювати. Я побачу, чи можу я це зробити, тоді оновіть свою відповідь, якщо це буде потрібно.
Ендрю Кунсе

@Dennis Здається, що інтерпретатор не обробляє аборти коду помилки *, тому я повертаю висновок. Я побачу, чи зможу завтра знайти іншого перекладача, щоб перевірити вихід.
Ендрю Кунсе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.