Ваша задача - вычислить наибольший общий делитель (GCD) из двух заданных целых чисел в минимально возможном количестве байтов кода.
Вы можете написать программу или функцию, получая ввод и возвращая вывод любым из наших общепринятых стандартных методов (включая STDIN / STDOUT, параметры функции / возвращаемые значения, аргументы командной строки и т. Д.).
На входе будут два неотрицательных целых числа. Вы должны иметь возможность обрабатывать либо полный диапазон, поддерживаемый целочисленным типом по умолчанию вашего языка, либо диапазон [0,255]
, в зависимости от того, что больше. Вам гарантировано, что хотя бы один из входов будет ненулевым.
Вы не можете использовать встроенные модули, которые вычисляют либо GCD, либо LCM (наименьшее общее кратное).
Применяются стандартные правила игры в гольф .
Тестовые случаи
0 2 => 2
6 0 => 6
30 42 => 6
15 14 => 1
7 7 => 7
69 25 => 1
21 12 => 3
169 123 => 1
20 142 => 2
101 202 => 101
источник
SIGFPE
.Ответы:
Сетчатка , 16
Это не использует алгоритм Евклида вообще - вместо этого он находит GCD, используя группы соответствия регулярному выражению.
Попробуйте онлайн. - В этом примере рассчитывается GCD (8,12).
Введите как 2 целых числа через пробел. Обратите внимание, что ввод / вывод в унарном виде. Если это не приемлемо, тогда мы можем сделать это:
Сетчатка, 30
Попробуйте онлайн.
Как указывает @ MartinBüttner, это распадается для больших чисел (как это обычно бывает для чего-то унарного). Как минимум, для ввода INT_MAX потребуется выделение строки размером 2 ГБ.
источник
+
s на*
s должна подойти. И вы можете значительно сократить последнюю стадию длинного кода, уменьшив его до1
.^
, потому что матч не может потерпеть неудачу со стартовой позиции.i386 (x86-32) машинный код, 8 байт (9B для без знака)
+1, если нам нужно обработать
b = 0
ввод.машинный код amd64 (x86-64), 9 байтов (10B для неподписанных или
14B13B для 64-целых чисел со знаком или без знака)109B для неподписанного на amd64, который разрывается при любом входе = 0Входы 32bit ненулевые подписанные целые числа
eax
иecx
. Выход вeax
.Эта структура цикла не проходит тестовый случай, где
ecx = 0
. (div
вызывает#DE
аппаратное выполнение при делении на ноль. (В Linux ядро выдаетSIGFPE
(исключение с плавающей запятой).) Если бы точка входа в цикл была прямо передinc
, мы бы избежали этой проблемы. Версия x86-64 может справиться с этим бесплатно смотрите ниже.Ответ Майка Шланты был отправной точкой для этого . Мой цикл делает то же самое, что и его, но для целых чисел со
cdq
знаком, потому что он на один байт корочеxor edx,edx
. И да, он работает правильно с одним или обоими входами отрицательными. Версия Майка будет работать быстрее и занимать меньше места в кэше UOP (xchg
на процессорах Intel это 3 мопа, аloop
на большинстве процессоров она очень медленная ), но эта версия выигрывает при размере машинного кода.Сначала я не заметил, что вопрос требует 32-разрядного без знака . Возвращение к
xor edx,edx
вместоcdq
будет стоить один байт.div
имеет такой же размер, какidiv
и все остальное, может оставаться неизменным (xchg
для перемещения данных и приinc/loop
этом работы).Интересно, что для 64-битного размера операнда (
rax
иrcx
) версии со знаком и без знака имеют одинаковый размер. Подписанная версия нуждается в префиксе REX дляcqo
(2B), но неподписанная версия все еще может использовать 2Bxor edx,edx
.В 64-битном коде
inc ecx
это 2B: однобайтовыеinc r32
иdec r32
коды операций были переназначены как префиксы REX.inc/loop
не сохраняет размер кода в 64-битном режиме, так что вы тоже можетеtest/jnz
. Работа с 64-битными целыми числами добавляет еще один байт на инструкцию в префиксах REX, за исключениемloop
илиjnz
. Остальные могут иметь все нули в младшем 32b (напримерgcd((2^32), (2^32 + 1))
), поэтому мы должны протестировать весь rcx и не можем сохранить байт с помощьюtest ecx,ecx
. Однако более медленныйjrcxz
insn составляет всего 2B, и мы можем поместить его в верхнюю часть цикла для обработкиecx=0
при входе :Полная работоспособная программа испытаний , включающие в себя ,
main
что работаетprintf("...", gcd(atoi(argv[1]), atoi(argv[2])) );
источник и выход ASM на Godbolt Compiler проводнике , для 32 и 64b версий. Протестировано и работает для 32bit (-m32
), 64bit (-m64
) и x32 ABI (-mx32
) .Также включены: версия, использующая только повторное вычитание , которая составляет 9B для без знака, даже для режима x86-64, и может принимать один из своих входов в произвольном регистре. Тем не менее, он не может обрабатывать ни один из входов,
sub
равный 0 на входе (он обнаруживает, когда выдает ноль, чего никогда не делает x - 0).Встроенный источник GNU C для 32-битной версии (скомпилировать с
gcc -m32 -masm=intel
)Обычно я пишу целую функцию в asm, но встроенный asm в GNU C кажется лучшим способом включить фрагмент, который может иметь входы / выходы в любых регистрах, которые мы выберем. Как вы можете видеть, встроенный синтаксис GNU C делает asmd уродливым и шумным. Это также очень сложный способ изучения асма .
На самом деле он будет компилироваться и работать в
.att_syntax noprefix
режиме, потому что все используемые insns являются либо одиночным / без операнда, либоxchg
. Не очень полезное наблюдение.источник
jrcxz
версии uint64_t :). Кроме того, я не заметил, что вы указали unsigned, поэтому я также включил подсчет байтов.jecxz
в 32-битной версии с тем же эффектом?inc/loop
3 байта в 32-битной версии, но 4B в 64-битной версии. Это означает, что только в 64-битной версии он не требует дополнительных байтовjrcxz
иjmp
вместоinc / loop
.Гексагония , 17 байт
Развернутая:
Попробуйте онлайн!
Установка его в сторону длины 3 была на одном дыхании. Срезать эти два байта в конце не было ... Я также не уверен, что это оптимально, но я уверен, что думаю, что это близко.
объяснение
Еще одна реализация евклидова алгоритма.
Программа использует три края памяти, которые я назову A , B и C , с указателем памяти (MP), начинающимся как показано:
Вот схема потока управления:
Поток управления начинается на сером пути с короткого линейного бита для ввода:
Обратите внимание, что код теперь оборачивается по краям
<
в левом углу. Это<
действует как ветвь. Если текущий фронт равен нулю (т. Е. Завершается евклидов алгоритм), IP отклоняется влево и выбирает красный путь. В противном случае итерация евклидова алгоритма вычисляется на зеленом пути.Сначала рассмотрим зеленый путь. Обратите внимание, что
>
и\
все действует как зеркала, которые просто отклоняют указатель инструкции. Также обратите внимание, что поток управления оборачивается по краям три раза, один раз снизу вверх, один раз из правого угла в нижний ряд и, наконец, из нижнего правого угла в левый угол, чтобы повторно проверить условие. Также обратите внимание, что.
нет опс.Это оставляет следующий линейный код для одной итерации:
Теперь мы вернулись к тому, с чего начали, за исключением того, что три ребра циклически меняли свои роли (исходный C теперь принимает роль B, а исходный B - роль A ...). По сути, мы перераспределили входные данные
A
иB
сB
иA % B
, соответственно.После того, как
A % B
(по краю C ) равен нулю, то НОД можно найти на кромке B . Опять же>
просто отклоняет IP, поэтому на красном пути мы выполняем:источник
32-битный машинный код с прямым порядком байтов x86, 14 байтов
Создано с помощью
nasm -f bin
d231 f3f7 d889 d389 db85 f475
источник
cdq
и подписанныйidiv
, и один байтxchg eax, r32
вместоmov
. Для 32-битного кода:inc/loop
вместоtest/jnz
(я не мог найти способ использоватьjecxz
, и нетjecxnz
). Я опубликовал свою окончательную версию в качестве нового ответа, так как считаю, что изменения достаточно велики, чтобы оправдать это.T-SQL, 153
169байтКто-то упомянул худший язык для игры в гольф?
Создает табличную функцию,
которая использует рекурсивный запрос для определения общих делителей. Тогда он возвращает максимум. Теперь использует евклидов алгоритм для определения GCD, полученного из моего ответа здесь .Пример использования
источник
Желе, 7 байт
Рекурсивная реализация евклидова алгоритма. Попробуйте онлайн!
Если бы встроенные модули не были запрещены,
g
(1 байт, встроенный GCD) достиг бы лучшего результата.Как это работает
источник
Haskell, 19 байтов
Пример использования:
45 # 35
->5
.Евклид, снова.
PS: конечно есть и встроенная
gcd
тоже.источник
0
или продолжает с модулем.Prelude
Python 3, 31
Сохранено 3 байта благодаря Sp3000.
источник
from math import*;gcd
g=lambda a,b:b and g(b,a%b)or a
MATL ,
119 байтКажется, никто до сих пор не использовал грубую силу, так что вот она.
Ввод представляет собой массив столбцов с двумя числами (используется в
;
качестве разделителя).Попробуйте онлайн! или проверьте все контрольные примеры .
объяснение
источник
C, 38 байт
источник
g
вместоgcd
.C, 28 байтов
Довольно простая функция, реализующая алгоритм Евклида. Возможно, можно стать короче, используя альтернативный алгоритм.
Если кто-то пишет небольшую главную обертку
тогда можно проверить несколько значений:
источник
Лабиринт , 18 байт
Завершается с ошибкой, но сообщение об ошибке отправляется на STDERR.
Попробуйте онлайн!
Это пока не совсем оптимально, но я не вижу способа сжать цикл ниже 3х3 в этой точке.
объяснение
Это использует евклидов алгоритм.
Во-первых, есть линейный бит для чтения ввода и попадания в основной цикл. Указатель инструкций (IP) начинается в верхнем левом углу и идет на восток.
Теперь мы вводим своего рода цикл while-do, который вычисляет евклидов алгоритм. Вершины стеков содержат
a
иb
(поверх неявного бесконечного количества нулей, но они нам не понадобятся). Мы будем представлять стеки из стороны в сторону, растущие навстречу друг другу:Цикл заканчивается один раз
a
ноль. Итерация цикла работает следующим образом:Вы можете видеть, мы заменили
a
иb
наb%a
иa
соответственно.Наконец, когда
b%a
ноль, IP продолжает двигаться на восток и выполняет:источник
Юлия,
2115 байтРекурсивная реализация евклидова алгоритма. Попробуйте онлайн!
Если встроенные модули не были запрещены,
gcd
(3 байта, встроенный GCD) добились бы лучшего результата.Как это работает
источник
Cubix , 10
12байтПопробуй здесь
Это оборачивает куб следующим образом:
Использует евклидов метод.
II
Два числа берутся из STDIN и помещают в стек./
Поток отражается до%
Mod of Top of Stack. Остаток слева на вершине стека.?
Если TOS 0, то продолжить, в противном случае повернуть направо.v
Если нет 0, тогда перенаправить вниз иu
повернуть направо дважды назад на мод./
Если 0 обойти куб,;
отбросить TOS отражателя ,O
вывести TOS и@
завершитьисточник
0,x
иx,0
... потом я наткнулся на это. Хороший!C #, 24 байта
источник
Пакет Windows, 76 байт
Рекурсивная функция. Назовите это как
GCD a b
с именем файлаgcd
.источник
MATL, 7 байт
Попробуйте онлайн!
объяснение
Поскольку мы не можем явно использовать встроенную функцию GCD (
Zd
в MATL), я использовал тот факт, что наименьшее общее кратноеa
иb
кратное наибольшему общему знаменателюa
иb
равно произведениюa
иb
.источник
*1MZm/
Ракетка (схема), 44 байта
Реализация Евклида в Ракетке (Схема)
Изменить: не видел решение @Numeri лол. Каким-то образом мы получили один и тот же код независимо друг от друга
источник
> <> , 32 байта
Принимает два значения из стека и применяет евклидовый алгоритм для создания их GCD.
Вы можете попробовать это здесь !
Чтобы получить лучший ответ в> <>, посмотрите Sok's !
источник
ReRegex , 23 байта
Работает идентично ответу Retina.
Попробуйте онлайн!
источник
GML, 57 байт
источник
Delphi 7, 148
Ну, я думаю, что нашел новый худший язык для игры в гольф.
источник
Хун, 20 байт
-
Хун №2, 39 байт
Как ни странно, единственной реализацией в stdlib Хуна для GCD является та, которая используется для ее криптографии RSA, которая также возвращает некоторые другие значения. Я должен обернуть его в функцию, которая занимает только
d
из вывода.Другая реализация - просто рекурсивное определение GCD по умолчанию.
источник
Python 3,5,
70,82,73 байта:В
not
этом случае убедитесь, что сумма всех чисел по*args
модулюi
равна нулю.Кроме того, теперь эта лямбда-функция может принимать столько значений, сколько вы хотите, при условии, что количество значений в
>=2
отличие отgcd
функции математического модуля. Например, он может принимать значения2,4,6,8,10
и возвращать правильный GCD, равный 2.источник
Рубин, 23 байта
помните, что рубиновые блоки вызываются с помощью g [...] или g.call (...) вместо g (...)
частичные кредиты voidpigeon
источник
g.call(a,b)
тебя можно использоватьg[a,b]
. Вместоproc{|a,b|
, вы можете использовать->a,b{
.b>0
вместоb<=0
и переключая порядок других операндов.Машинный код ARM, 12 байт:
монтаж:
В настоящее время не может скомпилировать это, но каждая инструкция в ARM занимает 4 байта. Вероятно, это можно было бы проиграть, используя режим THUMB-2.
источник
r0 > r1
затемsublt
ничего не будет делать (lt
предикат ложен) иbne
будет бесконечный цикл. Я думаю, что вам нужен обмен, если нетlt
, поэтому тот же цикл можно сделатьb-=a
или поa-=b
мере необходимости. Или отрицание, если субпроизводитель нести (иначе заимствовать).cmp r0, r1
/subgt r0, r0, r1
/sublt r1, r1, r0
/bne gcd
. Это 16B в инструкциях ARM, может быть 12 в инструкциях thumb2?sub ecx, eax
/jae .no_swap
/add ecx,eax
/xchg ecx,eax
/jne
. Таким образом, вместо cmp, я просто саб, затем отменить и заменить, если саб должен был пойти другим путем. Я проверил это, и это работает. (add
не выполнитjne
выход в неправильное время, потому что он не может произвести ноль, если только один из входов не был нулевым для начала, и мы не поддерживаем это. Обновление: нам нужно, чтобы любой вход был нулевым: /)ite
инструкция: если-то-еще. Должно быть идеально подходит для cmp / sub в одну сторону / sub в другую сторону.TI-Basic, 10 байтов
Не конкурирует из-за нового правила, запрещающего встроенные функции gcd
17-байтовое решение без
gcd(
встроенногоНе конкурирует из-за нового правила, запрещающего встроенные модули lcm
27-байтовое решение без
gcd(
или соlcm(
встроенным:35 байт рекурсивное решение без
gcd(
илиlcm(
встроенных модулей (требуется 2,53 операционной системы MP или выше, должны быть названыprgmG
):Вы передадите аргументы в рекурсивный вариант, как,
{A,B}
например{1071, 462}:prgmG
, в результате21
.источник
prgmG
.05AB1E , 10 байтов
Код:
Попробуйте онлайн!
Со встроенными модулями:
Объяснение:
Попробуйте онлайн! или попробуйте с несколькими номерами .
источник
Oracle SQL 11.2,
104118 байтИсправлено для ввода 0
источник
SELECT MAX(LEVEL)FROM DUAL WHERE MOD(:1,LEVEL)+MOD(:2,LEVEL)=0 CONNECT BY LEVEL<=:1+:2;
> <> , 12 + 3 = 15 байт
Ожидает, что входные числа будут присутствовать в стеке, поэтому +3 байта для
-v
флага.Попробуйте онлайн!Еще одна реализация евклидова алгоритма.
источник