Twoim zadaniem jest obliczenie największego wspólnego dzielnika (GCD) z dwóch podanych liczb całkowitych w jak najmniejszej liczbie bajtów kodu.
Możesz napisać program lub funkcję, przyjmując dane wejściowe i zwracając dane wyjściowe za pomocą dowolnej z naszych akceptowanych standardowych metod (w tym STDIN / STDOUT, parametry funkcji / zwracane wartości, argumenty wiersza polecenia itp.).
Dane wejściowe będą dwie nieujemne liczby całkowite. Powinieneś być w stanie obsłużyć albo pełny zakres obsługiwany przez domyślny typ liczb całkowitych twojego języka, albo zakres [0,255]
, w zależności od tego, który jest większy. Masz gwarancję, że co najmniej jedno z wejść będzie niezerowe.
Nie wolno używać wbudowanych funkcji obliczających GCD lub LCM (najmniejszą wspólną wielokrotność).
Obowiązują standardowe zasady gry w golfa .
Przypadki testowe
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
źródło
SIGFPE
.Odpowiedzi:
Retina , 16 lat
W ogóle nie korzysta z algorytmu Euclid - zamiast tego znajduje GCD za pomocą grup dopasowania wyrażeń regularnych.
Wypróbuj online. - W tym przykładzie obliczono GCD (8,12).
Wprowadź jako 2 liczby całkowite oddzielone spacjami. Zauważ, że I / O jest jednoargumentowy. Jeśli nie jest to do zaakceptowania, możemy to zrobić:
Retina, 30
Wypróbuj online.
Jak zauważa @ MartinBüttner, to rozpada się na duże liczby (jak to zwykle ma miejsce w przypadku wszystkiego, co jednoargumentowe). Co najmniej wejście INT_MAX będzie wymagało alokacji ciągu 2 GB.
źródło
+
s na*
s powinna zrobić. Możesz znacznie skrócić ostatni etap długiego kodu, redukując go do1
.^
, ponieważ niemożliwe jest, aby dopasowanie nie powiodło się z pozycji wyjściowej.Kod maszynowy i386 (x86-32), 8 bajtów (9B dla niepodpisanych)
+ 1B, jeśli musimy obsłużyć
b = 0
dane wejściowe.amd64 (x86-64) kod maszynowy, 9 bajtów (10B dla niepodpisanych lub
14B13B dla liczb całkowitych 64b podpisanych lub niepodpisanych)109B dla bez znaku na amd64, który psuje się przy obu wejściach = 0Wejścia są 32bit niezerowe podpisane liczby całkowite
eax
iecx
. Wyjście weax
.Ta struktura pętli zawodzi w przypadku testowym, w którym
ecx = 0
. (div
powoduje wykonanie#DE
sprzętu przy dzieleniu przez zero. (W Linuksie jądro dostarczaSIGFPE
(wyjątek zmiennoprzecinkowy)). Jeśli punkt wejścia do pętli był tuż przedinc
, uniknęlibyśmy problemu. Wersja x86-64 może sobie z tym poradzić za darmo, patrz poniżej.Odpowiedź Mike Shlanta była punktem wyjścia . Moja pętla robi to samo, co jego, ale dla liczb całkowitych ze
cdq
znakiem, ponieważ jest o jeden bajt krótsza niżxor edx,edx
. I tak, działa poprawnie z jednym lub dwoma wejściami ujemnymi. Wersja Mike'a będzie działać szybciej i zajmie mniej miejsca w pamięci podręcznej uop (xchg
jest 3 uops na procesorach Intela iloop
jest naprawdę wolna na większości procesorów ), ale ta wersja wygrywa przy rozmiarze kodu maszynowego.Z początku nie zauważyłem, że pytanie wymaga niepodpisanego 32-bitowego. Powrót do
xor edx,edx
zamiastcdq
kosztowałby jeden bajt.div
ma taki sam rozmiar jakidiv
i wszystko inne może pozostać niezmienione (xchg
do przenoszenia danych iinc/loop
nadal działać).Co ciekawe, dla 64- bitowego rozmiaru operandu (
rax
ircx
) wersje podpisane i niepodpisane mają ten sam rozmiar. Podpisana wersja wymaga prefiksu REX dlacqo
(2B), ale wersja bez znaku może nadal używać 2Bxor edx,edx
.W kodzie 64-bitowym
inc ecx
jest 2B: jednobajtoweinc r32
idec r32
opcodes zostały zmienione na prefiksy REX.inc/loop
nie zapisuje żadnego rozmiaru kodu w trybie 64-bitowym, więc równie dobrze możesztest/jnz
. Operowanie na 64-bitowych liczbach całkowitych dodaje kolejny jeden bajt na instrukcję w prefiksach REX, z wyjątkiemloop
lubjnz
. Reszta może mieć wszystkie zera na niskim 32b (np.gcd((2^32), (2^32 + 1))
), Więc musimy przetestować cały rcx i nie możemy zapisać bajtutest ecx,ecx
. Jednak wolniejszyjrcxz
insn to tylko 2B i możemy go umieścić na górze pętli, aby obsłużyćecx=0
przy wejściu :W pełni działający program testowy, w tym program
main
uruchamiającyprintf("...", gcd(atoi(argv[1]), atoi(argv[2])) );
źródło i asm w programie Godbolt Compiler Explorer , dla wersji 32 i 64b. Testowane i działające dla 32-bitowych (-m32
), 64-bitowych (-m64
) i x32 ABI (-mx32
) .Zawiera także: wersję wykorzystującą tylko powtarzane odejmowanie , która wynosi 9B dla niepodpisanego, nawet dla trybu x86-64, i może przyjmować jedno z danych wejściowych w dowolnym rejestrze. Jednak nie może obsłużyć żadnego z wejść przy wejściu 0 (wykrywa, kiedy
sub
tworzy zero, czego x-0 nigdy nie robi).GNU C wbudowane źródło asm dla wersji 32-bitowej (kompilacja z
gcc -m32 -masm=intel
)Normalnie napisałbym całą funkcję w asm, ale wbudowany asm GNU C wydaje się być najlepszym sposobem na włączenie fragmentu, który może mieć wejścia / wyjścia w dowolnych regach, które wybieramy. Jak widać, wbudowana składnia asm GNU C powoduje, że asm jest brzydki i głośny. To także bardzo trudny sposób na naukę asm .
W rzeczywistości skompilowałby się i działałby w
.att_syntax noprefix
trybie, ponieważ wszystkie użyte insny to albo pojedynczy / brak operandu, alboxchg
. Niezbyt przydatna obserwacja.źródło
jrcxz
końcu w wersji uint64_t :). Nie zauważyłem też, że podałeś niepodpisany, więc dołączyłem do tego również liczbę bajtów.jecxz
w wersji 32-bitowej z tym samym skutkiem?inc/loop
ma 3 bajty w wersji 32-bitowej, ale 4B w wersji 64-bitowej. Oznacza to, że w wersji 64-bitowej tylko, że nie kosztuje dodatkowych bajtów do używaniajrcxz
ijmp
zamiastinc / loop
.Sześciokąt , 17 bajtów
Rozłożony:
Wypróbuj online!
Dopasowanie go do boku o długości 3 było dziecinnie proste. Golenie tych dwóch bajtów na końcu nie było ... Nie jestem również przekonany, czy to optymalne, ale jestem pewien, że myślę, że jest blisko.
Wyjaśnienie
Kolejna implementacja algorytmu euklidesowego.
Program wykorzystuje trzy krawędzie pamięci, które nazywam A , B i C , przy czym wskaźnik pamięci (MP) zaczyna się tak, jak pokazano:
Oto schemat kontrolny:
Przepływ sterowania rozpoczyna się na szarej ścieżce krótkim bitem liniowym do wprowadzania:
Zauważ, że kod jest teraz zawijany wokół krawędzi do
<
lewego rogu. To<
działa jak gałąź. Jeśli bieżąca krawędź wynosi zero (tzn. Algorytm euklidesowy kończy się), adres IP jest odchylany w lewo i przechodzi na czerwoną ścieżkę. W przeciwnym razie iteracja algorytmu euklidesowego jest obliczana na zielonej ścieżce.Najpierw rozważymy zieloną ścieżkę. Należy pamiętać, że
>
i\
wszystko działa jak lustra, które po prostu odchyliłyby wskaźnik instrukcji. Należy również pamiętać, że przepływ kontrolny owija się wokół krawędzi trzy razy, raz od dołu do góry, raz od prawego rogu do dolnego rzędu i wreszcie od prawego dolnego rogu do lewego rogu, aby ponownie sprawdzić warunek. Zauważ też, że.
nie ma operacji.To pozostawia następujący kod liniowy dla pojedynczej iteracji:
Teraz jesteśmy z powrotem tam, gdzie zaczęliśmy, z tą różnicą, że trzy krawędzie zmieniały swoje role cyklicznie (pierwotne C przyjmuje teraz rolę B, a oryginalne B rolę A ...). W efekcie mamy relpaced wejść
A
iB
zB
iA % B
odpowiednio.Raz
A % B
(na krawędzi C ) wynosi zero, GCD znajduje się na krawędzi B . Ponownie po>
prostu odchyla adres IP, więc na czerwonej ścieżce wykonujemy:źródło
32-bitowy kod maszynowy little-endian x86, 14 bajtów
Wygenerowano za pomocą
nasm -f bin
d231 f3f7 d889 d389 db85 f475
źródło
cdq
i podpisałemidiv
, i jeden bajtxchg eax, r32
zamiastmov
. Dla kodu 32-bitowego:inc/loop
zamiasttest/jnz
(nie mogłem znaleźć sposobu użyciajecxz
i nie majecxnz
). Ostateczną wersję opublikowałem jako nową odpowiedź, ponieważ uważam, że zmiany są wystarczająco duże, aby to uzasadnić.T-SQL, 153
169bajtówKtoś wspomniał o najgorszym języku do gry w golfa?
Tworzy funkcję cenioną w tabeli,
która wykorzystuje zapytanie rekurencyjne w celu opracowania wspólnych dzielników. Następnie zwraca maksimum. Teraz używa algorytmu euklidesowego do ustalenia GCD pochodzącego z mojej odpowiedzi tutaj .Przykładowe użycie
źródło
Galaretka, 7 bajtów
Rekurencyjna implementacja algorytmu euklidesowego. Wypróbuj online!
Gdyby wbudowane nie były zabronione,
g
(1 bajt, wbudowany GCD) osiągnąłby lepszy wynik.Jak to działa
źródło
Haskell, 19 bajtów
Przykład użycia:
45 # 35
->5
.Znowu Euclid.
PS: oczywiście jest też wbudowany
gcd
.źródło
0
lub kontynuuje moduł.Prelude
Python 3, 31
Zaoszczędzono 3 bajty dzięki Sp3000.
źródło
from math import*;gcd
g=lambda a,b:b and g(b,a%b)or a
MATL ,
119 bajtówDo tej pory nikt nie używał brutalnej siły, więc oto jest.
Dane wejściowe to tablica kolumn z dwiema liczbami (używana
;
jako separator).Wypróbuj online! lub zweryfikuj wszystkie przypadki testowe .
Wyjaśnienie
źródło
C, 38 bajtów
źródło
g
zamiast zamiastgcd
.C, 28 bajtów
Dość prosta funkcja implementująca algorytm Euclida. Być może można skrócić się stosując alternatywny algorytm.
Jeśli ktoś pisze małe opakowanie główne
wtedy można przetestować kilka wartości:
źródło
Labirynt , 18 bajtów
Kończy się z błędem, ale komunikat o błędzie trafia do STDERR.
Wypróbuj online!
Nie wydaje mi się to jeszcze optymalne, ale w tej chwili nie widzę sposobu na kompresję pętli poniżej 3x3.
Wyjaśnienie
Wykorzystuje to algorytm euklidesowy.
Po pierwsze, istnieje liniowy bit do odczytu danych wejściowych i przejścia do głównej pętli. Wskaźnik instrukcji (IP) zaczyna się w lewym górnym rogu i kieruje się na wschód.
Teraz wchodzimy w rodzaj pętli while-do, która oblicza algorytm euklidesowy. Wierzchołki stosów zawierają
a
ib
(na domniemaną nieskończoną liczbę zer, ale nie będziemy ich potrzebować). Będziemy reprezentować stosy obok siebie, rosnąc ku sobie:Pętla kończy się raz, gdy
a
wynosi zero. Iteracja pętli działa w następujący sposób:Można zobaczyć, jakie otrzymuje
a
ib
zb%a
ia
odpowiednio.Wreszcie, gdy
b%a
wynosi zero, adres IP przesuwa się na wschód i wykonuje:źródło
Julia,
2115 bajtówRekurencyjna implementacja algorytmu euklidesowego. Wypróbuj online!
Gdyby wbudowane nie były zabronione,
gcd
(3 bajty, wbudowany GCD) osiągnąłby lepszy wynik.Jak to działa
źródło
Cubix , 10
12bajtówWypróbuj tutaj
Spowalnia to kostkę w następujący sposób:
Wykorzystuje metodę euklidesową.
II
Dwie liczby są pobierane ze STDIN i umieszczane na stosie/
Odbicie przepływu%
Mod na górze stosu. Resztka pozostawiona na szczycie stosu?
Jeśli TOS 0, to kontynuuj, w przeciwnym razie skręć w prawov
Jeśli nie 0, przekieruj w dół iu
skręć dwa razy w prawo na mod/
Jeśli 0 przejdź wokół sześcianu do;
TOS odbicia ,O
wyślij TOS i@
zakończźródło
0,x
i drugie, ix,0
... natknąłem się na to. Niezłe!C #, 24 bajty
źródło
Pakiet Windows, 76 bajtów
Funkcja rekurencyjna. Nazwij to tak jak
GCD a b
z nazwą plikugcd
.źródło
MATL, 7 bajtów
Wypróbuj online!
Wyjaśnienie
Ponieważ nie możemy jednoznacznie użyć wbudowanej funkcji GCD (
Zd
w MATL), wykorzystałem fakt, że najmniej wspólna wielokrotnośća
ib
razy największy wspólny mianownika
ib
jest równa iloczynowia
ib
.źródło
*1MZm/
Rakieta (schemat), 44 bajty
Wdrożenie Euclid w Racket (schemat)
Edycja: Nie widziałem lol rozwiązania @Numeri. Jakoś otrzymaliśmy dokładnie ten sam kod niezależnie
źródło
> <> , 32 bajty
Akceptuje dwie wartości ze stosu i stosuje algorytm euklidesowy do wygenerowania GCD.
Możesz spróbować tutaj !
Aby uzyskać znacznie lepszą odpowiedź w> <>, sprawdź Sok's !
źródło
ReRegex , 23 bajty
Działa identycznie jak odpowiedź Retina.
Wypróbuj online!
źródło
GML, 57 bajtów
źródło
Delphi 7, 148
Myślę, że znalazłem nowy najgorszy język do gry w golfa.
źródło
Hoon, 20 bajtów
-
Hoon # 2, 39 bajtów
Co dziwne, jedyną implementacją w stdlib Hoon dla GCD jest ta używana w jego kryptografii RSA, która zwraca również inne wartości. Muszę zawinąć w funkcję, która bierze tylko
d
dane wyjściowe.Druga implementacja to tylko domyślna rekurencyjna definicja GCD.
źródło
Python 3.5,
708273 bajty:W
not
tym przypadku upewni się, że suma wszystkich liczb w*args
moduloi
wynosi zero.Ponadto, teraz ta funkcja lambda może przyjmować tyle wartości, ile chcesz, pod warunkiem, że ilość wartości jest
>=2
inna, niżgcd
funkcja modułu matematycznego. Na przykład może przyjmować wartości2,4,6,8,10
i zwracać prawidłowy GCD 2.źródło
Rubinowy, 23 bajty
pamiętaj, że ruby są wywoływane za pomocą g [...] lub g.call (...), zamiast g (...)
częściowe kredyty dla gołębia pustki
źródło
g.call(a,b)
ciebie możesz użyćg[a,b]
. Zamiast tegoproc{|a,b|
możesz użyć->a,b{
.b>0
zamiastb<=0
i zmieniając kolejność innych operandów.Kod maszynowy ARM, 12 bajtów:
montaż:
Obecnie nie można tego skompilować, ale każda instrukcja w ARM zajmuje 4 bajty. Prawdopodobnie można go zagrać w golfa za pomocą trybu THUMB-2.
źródło
r0 > r1
wtedysublt
nic nie zrobi (lt
predykat jest fałszem) ibne
będzie nieskończoną pętlą. Myślę, że potrzebujesz wymiany, jeśli nielt
, więc ta sama pętla może zrobićb-=a
luba-=b
w razie potrzeby. Lub negację, jeśli subprodukowany przenosi (aka pożyczyć).cmp r0, r1
/subgt r0, r0, r1
/sublt r1, r1, r0
/bne gcd
. To 16B w instrukcjach ARM, może 12 w instrukcjach thumb2?sub ecx, eax
/jae .no_swap
/add ecx,eax
/xchg ecx,eax
/jne
. Więc zamiast cmp, po prostu poddaję się, a następnie cofnij i zamień, jeśli okręt podwodny powinien pójść w drugą stronę. Przetestowałem to i działa. (add
nie dokonajne
wyjścia w niewłaściwym czasie, ponieważ nie może wygenerować zera, chyba że jedno z danych wejściowych było zerowe na początek, a my nie obsługujemy tego. Aktualizacja: musimy obsługiwać dowolne z wejść jako zero: /)ite
instrukcja: if-then-else. Powinien być idealny dla cmp / sub w jedną stronę / sub w drugą stronę.TI-Basic, 10 bajtów
Nie konkuruje z powodu nowej reguły zabraniającej wbudowania gcd
17 bajtowe rozwiązanie bez
gcd(
wbudowanegoNie konkuruje z powodu nowej reguły zabraniającej wbudowania lcm
27-bajtowe rozwiązanie bez
gcd(
lublcm(
wbudowane:35-bajtowe rozwiązanie rekurencyjne bez
gcd(
lublcm(
wbudowane (wymaga systemu operacyjnego 2,53 MP lub nowszego, należy je nazwaćprgmG
):Przekazywałbyś argumenty do wariantu rekurencyjnego, ponieważ
{A,B}
na przykład{1071, 462}:prgmG
dałoby to wynik21
.źródło
prgmG
.05AB1E , 10 bajtów
Kod:
Wypróbuj online!
Z wbudowanymi:
Wyjaśnienie:
Wypróbuj online! lub Wypróbuj z wieloma numerami .
źródło
Oracle SQL 11.2,
104118 bajtówNaprawiono dla wejścia 0
źródło
SELECT MAX(LEVEL)FROM DUAL WHERE MOD(:1,LEVEL)+MOD(:2,LEVEL)=0 CONNECT BY LEVEL<=:1+:2;
> <> , 12 + 3 = 15 bajtów
Oczekuje, że liczby wejściowe będą obecne na stosie, więc +3 bajty dla
-v
flagi. Wypróbuj online!Kolejna implementacja algorytmu euklidesowego.
źródło