Задний план
Adler-32 - это 32-битная контрольная сумма, изобретенная Марком Адлером в 1995 году, которая является частью широко используемой библиотеки zlib (также разработанной Adler). Adler-32 не так надежен, как 32-битная циклическая проверка избыточности , но - по крайней мере в программном обеспечении - он намного быстрее и проще в реализации.
Определение
Пусть B = [b 1 , ⋯, b n ] - байтовый массив.
Контрольная сумма Adler-32 для B определяется как результат low + 65536 × high , где:
низкий: = ((1 + b 1 + ⋯ + b n ) мод 65521)
высокая: = (((1 + b 1 ) + (1 + b 1 + b 2 ) + ⋯ (1 + b 1 + ⋯ + b n )) мод 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
источник
Ответы:
Желе,
1917 байтПопробуйте онлайн!
источник
⁹²¤
Mathematica, 46 байтов
Анонимная функция, которая принимает целочисленный массив и возвращает Adler-32 с некоторыми улучшениями от Mils и Martin (см. Комментарии).
миль - это тоже 46 байт , но быстрее:
источник
Юлия,
7346 байтовЭто анонимная функция, которая принимает массив и возвращает целое число. Чтобы вызвать его, назначьте его переменной.
Мы объединяем
sum(x) + 1
иsum(cumsum(x) + 1)
в массив, гдеx
находится входной массив, и берем каждое по модулю 65521. Затем мы вычисляем скалярное произведение с 1 и 4 8 , что дает нам(sum(x) + 1) + 4^8 * sum(cumsum(x) + 1)
, что в точности соответствует формуле Адлера-32.Попробуйте онлайн! (Включает все тестовые случаи)
Сохранено 27 байтов благодаря Sp3000 и Денису!
источник
Функция машинного кода x86-64:
3332 байта (или3130 байтов сint[]
вводом вместоchar[]
)Функция машинного кода x86-32: 31 байт
Как фрагмент кода in-asm GNU C: сохраняет
2B1B (толькоret
insn).Прокомментированный источник и тестовый драйвер на github
64-битная версия вызывается напрямую из C со стандартным ABI System V x86-64 (используя 2 фиктивных аргумента для получения аргументов в нужных мне регистрах). Пользовательские соглашения о вызовах не редкость для asm-кода, так что это бонусная функция.
32-битный машинный код сохраняет 1B, потому что объединение верхних и нижних половин
push16/push16 => pop32
работает только в 32-битном режиме. Для 32-битной функции потребуется специальное соглашение о вызовах. Мы не должны возражать против этого, но для вызова из C нужна функция-обертка.После обработки 4096
~
(ASCII 126) байтовhigh = 0x3f040000, low = 0x7e001
. Итакhigh
, самый важный бит еще не установлен. Мой код использует это, знак удлинителейeax
вedx:eax
сcdq
как способ обнуленияedx
.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 в ABD SysV amd64 (с красной зоной) .
Я также рассмотрел использование
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]
/loop
Это 5B.scas
это еще одна опция для увеличения указателя с помощью инструкции 1B в 64-битном режиме. (rdi
/edi
вместо тогоrsi
, чтобы мы взяли указатель argrdi
). Мы не можем использовать результат флага fromscas
как условие цикла, потому что мы не хотим сохранять значение eax равным нулю. Различное распределение регистров может сохранить байт после цикла.int[]
входПолный
uint8_t[]
набор функций - это «основной» ответ, потому что это более интересная задача. Распаковка вint[]
- это необоснованная вещь, чтобы попросить нашего абонента сделать это на этом языке, но это экономит 2B.Если мы возьмем наши входные данные как распакованный массив из 32-битных целых чисел, мы можем легко сохранить один байт (использовать
lodsd
и заменитьxor eax,eax / cdq
на простоxor edx,edx
).Мы можем сохранить еще один байт, обнулив edx с помощью
lodsd
/cdq
и реорганизовав цикл так, чтобы он загружал завершающий элемент 0 перед выходом. (Мы по-прежнему предполагаем, что он существует, хотя это массивint
, а не строка).Я также сделал непроверенную версию, которая использует
scasd
(1B версияadd edi,4
) иadd eax, [rdi]
вместоlodsd
, но это также 30 байтов. Экономия от использованияhigh
eax в конце цикла компенсируется большим кодом в другом месте. Преимущество этого метода заключается0
в том, что он не зависит от завершающего элемента на входе, что, возможно, нецелесообразно для распакованного массива, где нам также явно указана длина.C ++ 11 тестовый драйвер
Смотрите ссылку на github. Этот ответ становился слишком большим, и тестовый драйвер получил больше возможностей с большим кодом.
источник
int[]
если это было необходимо, или сохранить более 4 байтов кода или что-то в этом роде. У меня нет проблем с представлением решенияadler32(int[])
проблемы, но я чувствую, чтоadler32(char[])
проблема более интересна, поскольку это настоящая функция adler32. Это то, что я действительно хочу играть в гольф в асме. (И мне бы очень хотелось как-то сохранить еще один байт, поскольку в реальной жизни asm 33 байта = 48 байт, если используется следующая функцияALIGN 16
). Я думаю, я буду продолжать играть в гольф оба.do{}while(--len)
стиль цикла вместоwhile(len--){}
.MATL , 22 байта
Входными данными могут быть массив чисел или соответствующая строка ASCII.
Попробуйте онлайн!
объяснение
источник
На самом деле, 36 байт
Попробуйте онлайн!
Объяснение:
источник
Java, 84 байта
Если Java-решения всегда должны быть полностью компилируемым кодом, пожалуйста, дайте мне знать.
Ungolfed
Заметка
Вам придется преобразовать входные данные
String
вint[]
(int[]
на один байт корочеbyte[]
илиchar[]
).Выход
источник
Пит, 120 кодов
С размером кода 20:
Примечания / Как это работает?
Поскольку невозможно использовать массив или строку в качестве входных данных, эта программа работает, принимая ряд целых чисел (представляющих символы ASCII) в качестве входных данных. Сначала я думал об использовании символьных входов, но изо всех сил пытался найти хорошее решение для завершения, поэтому теперь оно заканчивается, когда вводится любое число меньше 1. Изначально это были только отрицательные значения для завершения, но мне пришлось изменить инициализацию после написания программы, так что теперь я не могу соответствовать требуемому
2
, только a1
(26/45 на изображении трассы). Это не имеет значения, потому что в соответствии с правилами вызова разрешены только печатные символы ascii.Долгое время боролся с повторным входом в цикл, хотя в конце концов я нашел довольно элегантное решение. Нет
pointer
илиswitch
операций, только интерпретатор работает в стенах, пока он не перейдет обратно в зеленый кодел для чтения ввода (43-> 44 на изображениях трассировки).Завершение цикла достигается сначала дублированием ввода, добавлением 1, а затем проверкой, если оно больше 1. Если это так, запускается средство выбора кодов, и выполнение продолжается по нижнему пути. Если это не так, программа смещается влево (ярко-желтые кодовые обозначения, 31/50 на изображениях трасс).
Поддерживаемый размер входных данных зависит от реализации интерпретатора, хотя было бы возможно поддерживать произвольно большой ввод с правильным интерпретатором (скажем, например, интерпретатор Java, который использует в
BigInteger
качестве внутренних значений)Только что увидел, что в настройку входит одно ненужное
DUP
иCC
(7-> 8-> 9 в следовых изображениях). Понятия не имею, как это случилось. Это, по сути, просто тупик, он 16 раз переключает средство выбора кода, что не приводит к изменениям.Npiet след изображения
Настройка и первый цикл:
Завершение цикла, выход и выход:
Выходы
Простите, если я включу только один вывод, это займет много времени для ввода: ^)
Npiet след для [65, -1]
источник
C89, 70 байт
Чтобы проверить (скомпилировать с
gcc -std=c89 -lm golf.c
):источник
zlib
выглядит источник? Хм ...for
вместоwhile
:for(h=0,l=1;*B;)h+=l+=*B++;
Лабиринт ,
37363231 байтПопробуйте онлайн!
Ввод в виде списка целых чисел. Программа завершается с ошибкой (сообщение об ошибке отправляется в STDERR).
объяснение
Лабиринтный праймер:
_
.Хотя код начинается с «комнаты» 4x2, на самом деле это два отдельных цикла «два на два», сжатых вместе. Просто IP-адрес придерживается одного цикла за раз из-за значений стека.
Таким образом, код начинается с цикла 2x2 (по часовой стрелке), который считывает ввод при вычислении суммы префикса:
Теперь у нас есть все суммы префиксов в стеке aux , а также копия суммы по всем значениям и
0
из EOF на main . При этом мы вводим еще один цикл 2x2 (по часовой стрелке), который суммирует все суммы префиксов для вычисленияHIGH
.Основной стек теперь имеет
LOW - 1
иHIGH
и ноль, за исключением того, что мы еще не взяли модуль. Остальная часть кода полностью линейна:IP теперь попадает в тупик и оборачивается.
+
И*
практически отсутствуют-OPS, из нулей в нижней части стека.36
Теперь оказывается в верхней части основного INTO63
, но два{{
тянуть два нуля из Окса на вершине. затем%
пытается разделить на ноль, что завершает программу.Обратите внимание, что в Лабиринте используются целые числа произвольной точности, поэтому откладывание по модулю до конца суммы не вызовет проблем с переполнением целых чисел.
источник
Python 2,
6058 байтДовольно простой подход. Это полная программа, которая принимает список целых чисел через STDIN, например
[72, 105, 33]
.(Спасибо @xnor за замечательный совет по псевдонимам и инициализации)
источник
H=h=65521
для инициализацииh
при псевдониме 65521.J, 30 байт
Это, вероятно, может быть сжато больше с другим поездом.
использование
Здесь
x $ y
создается список сx
копиямиy
.объяснение
источник
Октава,
5250 байтСохранено 2 байта благодаря @LuisMendo
Принимает массив целых чисел в качестве входных данных.
low берется из последнего элемента high (до суммирования) вместо точного вычисления суммы, сохраняя общий итог ... 1 байт !
Пробный прогон на идеоне .
источник
+B
. Я предполагаю, что спецификация ввода говорит, что вы можете взять целые числа, так что, возможно, я просто сделаю это.CJam,
3029 байтВвод в виде списка целых чисел.
Проверьте это здесь.
объяснение
источник
Perl 6 , 60 байт
Объяснение:
Тест:
источник
Python 3 (79 байт)
По решению Р. Капа.
Я заменил умножение на сдвиг и убрал пару скобок.
Поскольку я не могу оставлять комментарии, я сделал новый ответ.
источник
Схема, 195 байт
Если бы не все эти скобки ...
источник
Haskell,
5450 байтПример использования:
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,..]
), поэтому значениеsum
off отключено1
, что фиксируется добавлением-1
к списку перед суммированием.Редактировать: Спасибо @xnor за 4 байта.
источник
m
:m=(`mod`65521).sum g x=m(-1:scanl(+)1x)*4^8+m(1:x)
. Вероятно, есть лучший способ исправить суммы, чем предваряющий.JavaScript (ES7),
5250 байтES6 занимает 51 байт (замените 4 ** 8 на 65536). Если вы хотите строковую версию, то для 69 байтов:
Редактировать: 2 байта сохранены благодаря @ user81655.
источник
Функция ARM Thumb-2 принимает
uint8_t[]
: 40 байтов (36B для нестандартного ABI иint[]
)Особенности: не отложенный по модулю, поэтому входные данные произвольного размера хороши. На самом деле не использует инструкцию деления, поэтому она не медленная. (по крайней мере, не по этой причине: P)
Экономия от следующих менее строгих правил:
uint32_t[]
массив.Итак, в лучшем случае это 36В.
0x28 = 40 байт
Заметки:
Вместо того,
log%m
чтобы в конце, мы делаемif(low>=m) low-=m
внутри цикла. Если мы делаем низкие до высоких, мы знаем, что ни один из них не может превзойти2*m
, поэтому по модулю это просто вопрос вычитания или нет. Аcmp
и предикатsub
составляет всего 6В в режиме Thumb2. Стандартная идиома для%
8B в режиме Thumb2:Версия с неявной длиной
adler(char *)
имеет тот же размер кода, что и явная длинаadler(uint8_t[], uint32_t len)
. Мы можем установить флаги для условия выхода из цикла с помощью одной инструкции 2B в любом случае.Версия с неявной длиной имеет преимущество правильной работы с пустой строкой, вместо того, чтобы пытаться выполнить цикл 2 ^ 32 раза.
собрать / собрать с:
или
Без этого
-static
, запущенный процессqemu-arm
не нашел своего динамического компоновщика. (И да, я установить ARM кросс-Devel настройки только для этого ответа, потому что я думал , что моя основывается-вычитать идея была аккуратной.) На amd64 Ubuntu, установитьgcc-arm-linux-gnueabi
,g++-arm-linux-gnueabi
. Я нашел что-gdb-arm-none-eabi
то вроде плохо работающего соединенияqemu-arm -g port
.Комментарий источника:
test-adler32.cpp
имеет те же тестовые случаи, что иmain()
для моего ответа x86-64, но начинается так:источник
16-битная функция машинного кода x86: 32 байта с использованием пользовательского соглашения о вызовах
Аргументы в регистрах, и не сохраняющие регистры, кроме bp (и sp).
В 16-битном коде мы возвращаем 32-битное значение в
dx:ax
регистровой паре. Это означает, что нам не нужно тратить какие-либо инструкции на слияниеhigh
иlow
вeax
. (Это также сэкономит байты в 32- и 64-битном коде, но мы можем оправдать только разгрузку этой работы для вызывающей стороны в 16-битном коде.)Прокомментированный исходный код и тестовый драйвер на github (для x86 16, 32 и 64bit и ARM).
0x120 - 0x100 = 32 байта
Протестировано путем сборки того же кода для 32-битного режима, чтобы я мог вызывать его (с помощью функции-оболочки) из C, скомпилированного с
-m32
. Для меня 16-битный режим несколько интересен, системные вызовы DOS - нет. Все инструкции имеют явные операнды, кромеloop
иlodsb
, поэтому при сборке для 32-битного режима используются префиксы размера операнда. Та же инструкция, другая кодировка. Ноlodsb
в 32-битном режиме буду использовать[esi]
, так что эта версия для тестирования работает с 32-битными указателями (потому что мы не делаем никакой математики адреса или увеличения / сравнения указателя).Нет несоответствий. Мой тестовый жгут печатает сообщение, если есть несоответствие.
С 16-битными регистрами мы не можем отложить уменьшение по модулю до окончания цикла. Существует интересная разница между 16-битным и другими размерами операндов:
m = 65521
(0xFFF1
) больше половины 65536. Вычитаниеm
при переносе сохраняет значение ниже 2 * m, даже еслиhigh=0xFFF0 + 0xFFF0
. После цикла, сравнение и вычитание будет делать трюк, вместоdiv
.Я придумал новую технику для сокращения модуля по модулю после добавления, которое может производить перенос . Вместо обнуления верхней половины входного значения для
div
, используйтеsetc dl
для создания 32-разрядного дивиденда, содержащего результат неусеченного сложения (dh
уже обнулен). (div
делает 32b / 16b => 16-битное деление.)setcc
(3 байта) был введен с 386. Чтобы выполнить это на 286 или более ранней версии, лучшее, что я придумал, использует недокументированнуюsalc
инструкцию (установите AL из кода переноса) . Это однобайтовый код операцииsbb al,al
, поэтому мы могли бы использоватьsalc
/neg al
перед выполнениемxchg ax, dx
(что нам все равно нужно). Безsalc
, есть последовательность 4B:sbb dx,dx
/neg dx
. Мы не можем использовать 3Bsbb dx,dx
/inc dx
, потому что это будет подражать,setnc
а неsetc
.Я попытался использовать 32-битный размер операнда вместо обработки переноса, но не только
add
инструкции нуждаются в префиксе размера операнда. Инструкции по настройке констант и т. Д. Также нуждаются в префиксах размера операнда, поэтому он не стал самым маленьким.источник
Pyth,
252423 байта1 байт благодаря @Jakube .
Еще 1 байт благодаря @Jakube .
Попробуйте онлайн!
Перевод моего ответа в желе .
источник
Perl 5, 43 байта
42 байта, плюс 1
-aE
вместо-e
Ввод в виде десятичных целых чисел, разделенных пробелом.
Кончик моей шляпы Sp3000 , у которого я взял идеи для этого ответа.
Как это работает:
-a
,$.
начинается с 1 и@F
является входным массивом.$h
начинается с 0.$_
используетсяmap
как заполнитель для каждого элемента массива.map$h+=$.+=$_,@F
означает, что для каждого элемента@F
мы добавляем этот элемент в,$.
а затем добавляем$.
в$h
.$.%65521+$h%65521*4**8
(то есть($. % 65521) + ( ($h % 65521) * (4**8) )
иsay
(выводим) результат).источник
Фактор
112109103 байтТеперь , это буквальный перевод алгоритма в вопросе ... теперь, когда я действительно сделал это, знаете ли, правильным.
Ungolfed:
Ожидается любая последовательность чисел или строки (небольшая разница, хотя технически они не одинаковы).
Я не знаю, как это будет работать для данного ограничения в версии Factor, скомпилированной с 32-битным размером слова, но на моей 6-ГБ 64-битной машине с частотой 2,2 ГГц:
источник
Рубин, 91 байт
источник
Clojure, 109 байт
На основе @Mark Адлера решения .
Ungolfed
использование
источник
Javascript (130 символов в гольфе)
Ungolfed
Golfed
Вставьте в консоль разработчика, а затем передайте ей массив байтов, например:
И он вернет контрольную сумму на консоль
источник
TMP, 55 байт
3a1.3b0.1;4+a>T8%a>xFFF14+b>a8%b>xFFF11~5<b>164|b>a2$b$
Реализацию в Lua можно найти здесь: http://preview.ccode.gq/projects/TMP.lua
источник
Python 3.5, 82 байта:
( -1 байт благодаря Нейлу ! )
( -1 байт благодаря матмандану ! )
( -4 байта благодаря Денису ! )
Анонимная
lambda
функция. Принимает байтовый массив, применяет весь алгоритм к массиву и выводит результат. Успешно работал для всех тестовых случаев. Вы вызываете это, присваивая ему переменную, а затем вызывая эту переменную, как если бы вы вызывали обычную функцию. Если вы используете оболочку, то она должна выводиться без функции печати. Однако, если это не так, то вы должны обернуть вызов функции вprint()
функцию, чтобы увидеть результат.Попробуйте онлайн! (Ideone)
источник
(E+15)
на самом деле байт длиннее, чем65536
.4**8
на байт короче65536
.Деление , 324 байта
Честное предупреждение, единственная реализация, на которой я тестировал это, это мой собственный порт языка для F #. Это не игра в гольф, в основном потому, что мне было проще провести пару длинных пробежек, пока моя основная константа остыла вдоль дна, поэтому я могу вернуться и настроить ее.
Как это работает?
R'~++Y++~'L
Блок предохранителей 256 константу и запускает его вниз, установив массовый множитель реактора непосредственно под ним.R'~++A++~'A
Блок предохранителей еще 256 и запускает его вверх в направлении выше реактора, который делений частицы в двух массовых кратных65536
массе каждого, запуская их влево и вправо (где правая частица немедленно уничтожается терминатором).65521
(нашего большого прайма).Z
) в конце цикла заставляет частицу дублировать простое число, отправляя его обратно вправо, где оно в конечном итоге устанавливает сохраненную массу реактора деления (^
). Вот как мы будем применять оператор модуля к блоку H.<
), который мы будем использовать для L-блока.|S
«градирню».\Y/
соединяет блок L (который входит через левый канал) и блок H (который входит через правый канал), затем ударяет их в терминатор, который устанавливает код выхода для слитой массы.источник
*
, поэтому я возвращаю вывод. Я посмотрю, смогу ли я найти другого переводчика для проверки результатов завтра.