Największy wspólny dzielnik


40

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 .

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

1
Jeśli pozwalamy asmowi na wejście w dowolnych rejestrach, które są wygodne, a wynik w jakimkolwiek reg jest dogodny, zdecydowanie powinniśmy zezwalać na funkcje, a nawet fragmenty kodu (tj. Tylko treść funkcji). Uczynienie z mojej odpowiedzi kompletnej funkcji dodałoby około 4B z konwencją wywoływania rejestru, taką jak 32-bitowe wywołanie MS MS (jeden xchg eax, jeden mov i ret), lub więcej z konwencją wywoływania stosu.
Peter Cordes,

@PeterCordes Przepraszam, powinienem był być bardziej szczegółowy. Możesz całkowicie po prostu napisać niezbędny kod, ale jeśli byłbyś tak uprzejmy, aby podać sposób uruchomienia tego kodu, byłoby miło.
Mike Shlanta,

Więc policz tylko kod gcd, ale podaj otaczający kod, aby ludzie mogli weryfikować / eksperymentować / ulepszać? BTW, twoje przypadki testowe, w których zero jest jednym z dwóch wejść, łamią nasze odpowiedzi na kod maszynowy x86. div przez zero podnosi wyjątek sprzętowy. W systemie Linux proces otrzymuje SIGFPE.
Peter Cordes,

3
@CodesInChaos Pamięć i ograniczenia czasowe są zwykle ignorowane, o ile sam algorytm może w zasadzie obsłużyć wszystkie dane wejściowe. Reguła ma na celu po prostu uniknięcie kodowania przez ludzi arbitralnych limitów dla pętli, które sztucznie ograniczają algorytm do mniejszego zakresu danych wejściowych. Nie bardzo rozumiem, jak to się dzieje z niezmiennością?
Martin Ender

1
gcd (0, n) to błąd nie n
RosLuP

Odpowiedzi:


37

Retina , 16 lat

^(.+)\1* \1+$
$1

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

\d+
$*
^(.+)\1* \1+$
$1
1+
$.&

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.


2
Chciałbym głosować za tym więcej
MickyT,

Teraz powinno być dobrze z zakresem liczb. Zmieniłem specyfikację (za zgodą OP), aby wymagała tylko naturalnego zakresu liczbowego języka (lub [0,255], jeśli to więcej). Będziesz jednak musiał obsługiwać zera, chociaż myślę, że zmiana twojego +s na *s powinna zrobić. Możesz znacznie skrócić ostatni etap długiego kodu, redukując go do 1.
Martin Ender,

2
Do przyszłego użytku właśnie znalazłem alternatywne rozwiązanie 16-bajtowe, które działa na dowolną liczbę danych wejściowych (w tym jedną), więc może być bardziej przydatne w innych kontekstach: retina.tryitonline.net/...
Martin Ender

1
Zauważyłem tylko, że ani twoje rozwiązania, ani to w moim powyższym komentarzu nie potrzebują ^, ponieważ niemożliwe jest, aby dopasowanie nie powiodło się z pozycji wyjściowej.
Martin Ender,

28

Kod maszynowy i386 (x86-32), 8 bajtów (9B dla niepodpisanych)

+ 1B, jeśli musimy obsłużyć b = 0dane wejściowe.

amd64 (x86-64) kod maszynowy, 9 bajtów (10B dla niepodpisanych lub 14B 13B dla liczb całkowitych 64b podpisanych lub niepodpisanych)

10 9B dla bez znaku na amd64, który psuje się przy obu wejściach = 0


Wejścia są 32bit niezerowe podpisane liczby całkowite eaxi ecx. Wyjście w eax.

## 32bit code, signed integers:  eax, ecx
08048420 <gcd0>:
 8048420:       99                      cdq               ; shorter than xor edx,edx
 8048421:       f7 f9                   idiv   ecx
 8048423:       92                      xchg   edx,eax    ; there's a one-byte encoding for xchg eax,r32.  So this is shorter but slower than a mov
 8048424:       91                      xchg   ecx,eax    ; eax = divisor(from ecx), ecx = remainder(from edx), edx = quotient(from eax) which we discard
    ; loop entry point if we need to handle ecx = 0
 8048425:       41                      inc    ecx        ; saves 1B vs. test/jnz in 32bit mode
 8048426:       e2 f8                   loop   8048420 <gcd0>
08048428 <gcd0_end>:
 ; 8B total
 ; result in eax: gcd(a,0) = a

Ta struktura pętli zawodzi w przypadku testowym, w którym ecx = 0. ( divpowoduje wykonanie #DEsprzętu przy dzieleniu przez zero. (W Linuksie jądro dostarcza SIGFPE(wyjątek zmiennoprzecinkowy)). Jeśli punkt wejścia do pętli był tuż przed inc, 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 cdqznakiem, 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 ( xchgjest 3 uops na procesorach Intela i loopjest 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,edxzamiast cdqkosztowałby jeden bajt. divma taki sam rozmiar jak idivi wszystko inne może pozostać niezmienione ( xchgdo przenoszenia danych i inc/loopnadal działać).

Co ciekawe, dla 64- bitowego rozmiaru operandu ( raxi rcx) wersje podpisane i niepodpisane mają ten sam rozmiar. Podpisana wersja wymaga prefiksu REX dla cqo(2B), ale wersja bez znaku może nadal używać 2B xor edx,edx.

W kodzie 64-bitowym inc ecxjest 2B: jednobajtowe inc r32i dec r32opcodes zostały zmienione na prefiksy REX. inc/loopnie zapisuje żadnego rozmiaru kodu w trybie 64-bitowym, więc równie dobrze możesz test/jnz. Operowanie na 64-bitowych liczbach całkowitych dodaje kolejny jeden bajt na instrukcję w prefiksach REX, z wyjątkiem looplub jnz. 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ć bajtu test ecx,ecx. Jednak wolniejszy jrcxzinsn to tylko 2B i możemy go umieścić na górze pętli, aby obsłużyć ecx=0przy wejściu :

## 64bit code, unsigned 64 integers:  rax, rcx
0000000000400630 <gcd_u64>:
  400630:       e3 0b                   jrcxz  40063d <gcd_u64_end>   ; handles rcx=0 on input, and smaller than test rcx,rcx/jnz
  400632:       31 d2                   xor    edx,edx                ; same length as cqo
  400634:       48 f7 f1                div    rcx                      ; REX prefixes needed on three insns
  400637:       48 92                   xchg   rdx,rax
  400639:       48 91                   xchg   rcx,rax
  40063b:       eb f3                   jmp    400630 <gcd_u64>
000000000040063d <gcd_u64_end>:
## 0xD = 13 bytes of code
## result in rax: gcd(a,0) = a

W pełni działający program testowy, w tym program mainuruchamiający printf("...", 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 subtworzy zero, czego x-0 nigdy nie robi).

GNU C wbudowane źródło asm dla wersji 32-bitowej (kompilacja z gcc -m32 -masm=intel)

int gcd(int a, int b) {
    asm (// ".intel_syntax noprefix\n"
        // "jmp  .Lentry%=\n" // Uncomment to handle div-by-zero, by entering the loop in the middle.  Better: `jecxz / jmp` loop structure like the 64b version
        ".p2align 4\n"                  // align to make size-counting easier
         "gcd0:   cdq\n\t"              // sign extend eax into edx:eax.  One byte shorter than xor edx,edx
         "        idiv    ecx\n"
         "        xchg    eax, edx\n"   // there's a one-byte encoding for xchg eax,r32.  So this is shorter but slower than a mov
         "        xchg    eax, ecx\n"   // eax = divisor(ecx), ecx = remainder(edx), edx = garbage that we will clear later
         ".Lentry%=:\n"
         "        inc     ecx\n"        // saves 1B vs. test/jnz in 32bit mode, none in 64b mode
         "        loop    gcd0\n"
        "gcd0_end:\n"
         : /* outputs */  "+a" (a), "+c"(b)
         : /* inputs */   // given as read-write outputs
         : /* clobbers */ "edx"
        );
    return a;
}

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 noprefixtrybie, ponieważ wszystkie użyte insny to albo pojedynczy / brak operandu, albo xchg. Niezbyt przydatna obserwacja.


2
@MikeShlanta: Dzięki. Jeśli lubisz optymalizować asm, spójrz na niektóre z moich odpowiedzi na temat przepełnienia stosu. :)
Peter Cordes

2
@MikeShlanta: Znalazłem zastosowanie w jrcxzkoń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.
Peter Cordes,

Dlaczego nie można użyć jecxzw wersji 32-bitowej z tym samym skutkiem?
Cody Gray

1
@CodyGray: inc/loopma 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żywania jrcxzi jmpzamiast inc / loop.
Peter Cordes,

Nie możesz wskazać środka jako wejścia?
l4m2

14

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:

wprowadź opis zdjęcia tutaj

Oto schemat kontrolny:

wprowadź opis zdjęcia tutaj

Przepływ sterowania rozpoczyna się na szarej ścieżce krótkim bitem liniowym do wprowadzania:

?    Read first integer into memory edge A.
'    Move MP backwards onto edge B.
?    Read second integer into B.

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:

{    Move MP forward onto edge C.
'}   Move to A and back to C. Taken together this is a no-op.
=    Reverse the direction of the MP so that it now points at A and B. 
%    Compute A % B and store it in C.
)(   Increment, decrement. Taken together this is a no-op, but it's
     necessary to ensure that IP wraps to the bottom row instead of
     the top row.

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ść Ai Bz Bi A % Bodpowiednio.

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:

}    Move MP to edge B.
!    Print its value as an integer.
@    Terminate the program.

9

32-bitowy kod maszynowy little-endian x86, 14 bajtów

Wygenerowano za pomocą nasm -f bin

d231 f3f7 d889 d389 db85 f475

    gcd0:   xor     edx,edx
            div     ebx
            mov     eax,ebx
            mov     ebx,edx
            test    ebx,ebx
            jnz     gcd0

4
Zmniejszyłem to do 8 bajtów, używając cdqi podpisałem idiv, i jeden bajt xchg eax, r32zamiast mov. Dla kodu 32-bitowego: inc/loopzamiast test/jnz(nie mogłem znaleźć sposobu użycia jecxzi nie ma jecxnz). Ostateczną wersję opublikowałem jako nową odpowiedź, ponieważ uważam, że zmiany są wystarczająco duże, aby to uzasadnić.
Peter Cordes,

9

T-SQL, 153 169 bajtów

Ktoś wspomniał o najgorszym języku do gry w golfa?

CREATE FUNCTION G(@ INT,@B INT)RETURNS TABLE RETURN WITH R AS(SELECT 1D,0R UNION ALL SELECT D+1,@%(D+1)+@B%(D+1)FROM R WHERE D<@ and D<@b)SELECT MAX(D)D FROM R WHERE 0=R

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

SELECT * 
FROM (VALUES
        (15,45),
        (45,15),
        (99,7),
        (4,38)
    ) TestSet(A, B)
    CROSS APPLY (SELECT * FROM G(A,B))GCD

A           B           D
----------- ----------- -----------
15          45          15
45          15          15
99          7           1
4           38          2

(4 row(s) affected)

1
Jezus, który jest pełny.
Cyoce,

9

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

ṛß%ðḷṛ?  Main link. Arguments: a, b

   ð     Convert the chain to the left into a link; start a new, dyadic chain.
 ß       Recursively call the main link...
ṛ %        with b and a % b as arguments.
     ṛ?  If the right argument (b) is non-zero, execute the link.
    ḷ    Else, yield the left argument (a).

To prawie czuje się jak oszukiwanie haha, być może będę musiał sprecyzować, że w odpowiedziach nie można używać butlin ...
Mike Shlanta,

13
Jeśli zdecydujesz się to zrobić, powinieneś to zrobić szybko. Obecnie unieważniałoby trzy odpowiedzi.
Dennis,

Zauważ, że podana długość jest w bajtach - w UTF8 znaki te mają w większości> 1 bajt.
kora

8
@ korty Tak, wszystkie zawody w golfa kodowane są domyślnie w bajtach. Jednak Jelly nie używa UTF-8, ale niestandardową stronę kodową, która koduje każdy z 256 znaków, które rozumie jako pojedynczy bajt.
Dennis,

@Dennis ah, sprytny.
korty

7

Haskell, 19 bajtów

a#0=a
a#b=b#rem a b

Przykład użycia: 45 # 35-> 5.

Znowu Euclid.

PS: oczywiście jest też wbudowany gcd.


należy wyjaśnić sprawę, że odwraca kolejność wejścia, aby uniknąć czek warunkową
dumną haskeller

@proudhaskeller: jaka sztuczka? Każdy korzysta z tego algorytmu, tzn. Zatrzymuje się 0lub kontynuuje moduł.
nimi

Nevrmind, wszyscy używają tej sztuczki
dumny haskeller

To, mniej golfa, jest prawie dokładnie to, co jestPrelude
Michael Klein

6

Python 3, 31

Zaoszczędzono 3 bajty dzięki Sp3000.

g=lambda a,b:b and g(b,a%b)or a

3
W Python 3.5+:from math import*;gcd
Sp3000,

@ Sp3000 Nicea, nie wiedziałem, że przenieśli to do matematyki.
Morgan Thrapp,

1
Podczas gdy jesteś przy tym:g=lambda a,b:b and g(b,a%b)or a
Sp3000,

@ Sp3000 Thanks! Właśnie skończyłem rozwiązanie rekurencyjne, ale to nawet lepsze niż to, co miałem.
Morgan Thrapp,

Wbudowane dla GCD i LCM są niedozwolone, więc drugie rozwiązanie nie będzie poprawne.
mbomb007

6

MATL , 11 9 bajtów

Do tej pory nikt nie używał brutalnej siły, więc oto jest.

ts:\a~f0)

Dane wejściowe to tablica kolumn z dwiema liczbami (używana ;jako separator).

Wypróbuj online! lub zweryfikuj wszystkie przypadki testowe .

Wyjaśnienie

t     % Take input [a;b] implicitly. Duplicate
s     % Sum. Gives a+b
:     % Array [1,2,...,a+b]
\     % Modulo operation with broadcast. Gives a 2×(a+b) array
a~    % 1×(a+b) array that contains true if the two modulo operations gave 0
f0)   % Index of last true value. Implicitly display

5

C, 38 bajtów

g(x,y){while(x^=y^=x^=y%=x);return y;}

1
Musisz dołączyć definicję funkcji do swojego bajtu.
Rɪᴋᴇʀ

1
@Riker przepraszam za to, dodaję definicję i aktualizuję licznik
How Chen

Możesz zapisać dwa bajty, nazywając funkcję gzamiast zamiast gcd.
Steadybox

@ Steadybox ok, tak, po raz pierwszy dołącz do tej społeczności :)
How Chen

1
Witamy w PPCG!
Rɪᴋᴇʀ

4

C, 28 bajtów

Dość prosta funkcja implementująca algorytm Euclida. Być może można skrócić się stosując alternatywny algorytm.

g(a,b){return b?g(b,a%b):a;}

Jeśli ktoś pisze małe opakowanie główne

int main(int argc, char **argv)
{
  printf("gcd(%d, %d) = %d\n", atoi(argv[1]), atoi(argv[2]), g(atoi(argv[1]), atoi(argv[2])));
}

wtedy można przetestować kilka wartości:

$ ./gcd 6 21
gcd (6, 21) = 3
$ ./gcd 21 6
gcd (21, 6) = 3
$ ./gcd 6 8
gcd (6, 8) = 2
$ ./gcd 1 1
gcd (1, 1) = 1
$ ./gcd 6 16
gcd (6, 16) = 2
$ ./gcd 27 244
gcd (27, 244) = 1

4

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.

?    Read first integer from STDIN and push onto main stack.
}    Move the integer over to the auxiliary stack.
     The IP now hits a dead end so it turns around.
?    Read the second integer.
     The IP hits a corner and follows the bend, so it goes south.
:    Duplicate the second integer.
)    Increment.
     The IP is now at a junction. The top of the stack is guaranteed to be
     positive, so the IP turns left, to go east.
"    No-op.
%    Modulo. Since `n % (n+1) == n`, we end up with the second input on the stack.

Teraz wchodzimy w rodzaj pętli while-do, która oblicza algorytm euklidesowy. Wierzchołki stosów zawierają ai b(na domniemaną nieskończoną liczbę zer, ale nie będziemy ich potrzebować). Będziemy reprezentować stosy obok siebie, rosnąc ku sobie:

    Main     Auxiliary
[ ... 0 a  |  b 0 ... ]

Pętla kończy się raz, gdy awynosi zero. Iteracja pętli działa w następujący sposób:

=    Swap a and b.           [ ... 0 b  |  a 0 ... ]
{    Pull a from aux.        [ ... 0 b a  |  0 ... ]
:    Duplicate.              [ ... 0 b a a  |  0 ... ]
}    Move a to aux.          [ ... 0 b a  |  a 0 ... ]
()   Increment, decrement, together a no-op.
%    Modulo.                 [ ... 0 (b%a)  |  a 0 ... ]

Można zobaczyć, jakie otrzymuje ai bz b%ai aodpowiednio.

Wreszcie, gdy b%awynosi zero, adres IP przesuwa się na wschód i wykonuje:

{    Pull the non-zero value, i.e. the GCD, over from aux.
!    Print it.
     The IP hits a dead end and turns around.
{    Pull a zero from aux.
%    Attempt modulo. This fails due to division by 0 and the program terminates.

4

Julia, 21 15 bajtów

a\b=a>0?b%a\a:b

Rekurencyjna 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

a\b=             Redefine the binary operator \ as follows:
    a>0?     :       If a > 0:
        b%a\a        Resursively apply \ to b%a and a. Return the result.
              b      Else, return b.

4

Cubix , 10 12 bajtów

?v%uII/;O@

Wypróbuj tutaj

Spowalnia to kostkę w następujący sposób:

    ? v
    % u
I I / ; O @ . .
. . . . . . . .
    . .
    . .

Wykorzystuje metodę euklidesową.

IIDwie 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 prawo
vJeśli nie 0, przekieruj w dół i uskręć dwa razy w prawo na mod
/Jeśli 0 przejdź wokół sześcianu do
;TOS odbicia , Owyślij TOS i @zakończ


Właśnie napisałem 12-bajtową odpowiedź Cubix, a następnie zacząłem przewijać odpowiedzi, aby sprawdzić, czy muszę obsłużyć jedno 0,xi drugie, i x,0... natknąłem się na to. Niezłe!
ETHproductions


3

Pakiet Windows, 76 bajtów

Funkcja rekurencyjna. Nazwij to tak jak GCD a bz nazwą pliku gcd.

:g
if %2 equ 0 (set f=%1
goto d)
set/a r=%1 %% %2
call :g %2 %r%
:d
echo %f%

3

MATL, 7 bajtów

pG1$Zm/

Wypróbuj online!

Wyjaśnienie

Ponieważ nie możemy jednoznacznie użyć wbudowanej funkcji GCD ( Zdw MATL), wykorzystałem fakt, że najmniej wspólna wielokrotność ai brazy największy wspólny mianownik ai bjest równa iloczynowi ai b.

p       % Grab the input implicitly and multiply the two elements
G       % Grab the input again, explicitly this time
1$Zm    % Compute the least-common multiple
/       % Divide the two to get the greatest common denominator

Możesz zapisać jeden bajt dzięki dwóm osobnym wejściom:*1MZm/
Luis Mendo

3

Rakieta (schemat), 44 bajty

Wdrożenie Euclid w Racket (schemat)

(define(g a b)(if(= 0 b)a(g b(modulo a b))))

Edycja: Nie widziałem lol rozwiązania @Numeri. Jakoś otrzymaliśmy dokładnie ten sam kod niezależnie


Czy to działa w obu przypadkach?
NoOneIsHere

@NoOneIsHhe tak, to działa w obu
kronicmage

3

> <> , 32 bajty

::{::}@(?\=?v{:}-
.!09}}${{/;n/>

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 !


1
Dzisiaj znalazłem nowy język :)
nsane


2

GML, 57 bajtów

a=argument0
b=argument1
while b{t=b;b=a mod b;a=t}return a

2

Delphi 7, 148

Myślę, że znalazłem nowy najgorszy język do gry w golfa.

unit a;interface function g(a,b:integer):integer;implementation function g(a,b:integer):integer;begin if b=0then g:=a else g:=g(b,a mod b);end;end.

Och, nie wiem, nawiasy są dość słabe do gry w golfa
MickyT,

2

Hoon, 20 bajtów

|=
{@ @}
d:(egcd +<)

-

Hoon # 2, 39 bajtów

|=
{a/@ b/@}
?~
b
a
$(a b, b (mod a b))

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 ddane wyjściowe.

Druga implementacja to tylko domyślna rekurencyjna definicja GCD.


2

Python 3.5, 70 82 73 bajty:

lambda*a:max([i for i in range(1,max(*a)+1)if not sum(g%i for g in[*a])])

W nottym przypadku upewni się, że suma wszystkich liczb w *argsmodulo iwynosi zero.

Ponadto, teraz ta funkcja lambda może przyjmować tyle wartości, ile chcesz, pod warunkiem, że ilość wartości jest >=2inna, niż gcdfunkcja modułu matematycznego. Na przykład może przyjmować wartości 2,4,6,8,10i zwracać prawidłowy GCD 2.


1
Jesteś aresztowany za nazwy zmiennych wielu znaków. (Lub argumenty funkcji, ale cokolwiek)
CalculatorFeline

2

Rubinowy, 23 bajty

g=->a,b{b>0?a:g[b,a%b]}

pamiętaj, że ruby ​​są wywoływane za pomocą g [...] lub g.call (...), zamiast g (...)

częściowe kredyty dla gołębia pustki


2
Zamiast g.call(a,b)ciebie możesz użyć g[a,b]. Zamiast tego proc{|a,b|możesz użyć ->a,b{.
obfity

1
Możesz także zapisać jeden bajt, używając b>0zamiast b<=0i zmieniając kolejność innych operandów.
obfity

2

Kod maszynowy ARM, 12 bajtów:

montaż:

gcd: cmp r0, r1
     sublt r0, r0, r1
     bne gcd

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.


Niezły robotnik, każdy, kto robi to w kodzie maszynowym, dostaje ode mnie poważne rekwizyty.
Mike Shlanta,

Wydaje się, że jest to próba algo Euklidesa przy użyciu tylko odejmowania , ale nie sądzę, aby to działało. Jeśli r0 > r1wtedy subltnic nie zrobi ( ltpredykat jest fałszem) i bnebędzie nieskończoną pętlą. Myślę, że potrzebujesz wymiany, jeśli nie lt, więc ta sama pętla może zrobić b-=alub a-=bw razie potrzeby. Lub negację, jeśli subprodukowany przenosi (aka pożyczyć).
Peter Cordes,

W tym przewodniku zestawu instrukcji ARM w rzeczywistości zastosowano algorytm odejmowania GCD jako przykład predykcji. (str. 25). Używają cmp r0, r1/ subgt r0, r0, r1/ sublt r1, r1, r0/ bne gcd. To 16B w instrukcjach ARM, może 12 w instrukcjach thumb2?
Peter Cordes,

1
Na x86 zarządzałem 9 bajtami za pomocą: 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. ( addnie dokona jnewyjś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: /)
Peter Cordes,

W przypadku Thumb2 istnieje iteinstrukcja: if-then-else. Powinien być idealny dla cmp / sub w jedną stronę / sub w drugą stronę.
Peter Cordes,

2

TI-Basic, 10 bajtów

Prompt A,B:gcd(A,B

Nie konkuruje z powodu nowej reguły zabraniającej wbudowania gcd


17 bajtowe rozwiązanie bez gcd(wbudowanego

Prompt A,B:abs(AB)/lcm(A,B

Nie konkuruje z powodu nowej reguły zabraniającej wbudowania lcm


27-bajtowe rozwiązanie bez gcd(lub lcm(wbudowane:

Prompt A,B:While B:B→T:BfPart(A/B→B:T→A:End:A

35-bajtowe rozwiązanie rekurencyjne bez gcd(lub lcm(wbudowane (wymaga systemu operacyjnego 2,53 MP lub nowszego, należy je nazwać prgmG ):

If Ans(2:Then:{Ans(2),remainder(Ans(1),Ans(2:prgmG:Else:Disp Ans(1:End

Przekazywałbyś argumenty do wariantu rekurencyjnego, ponieważ {A,B}na przykład {1071, 462}:prgmGdałoby to wynik 21.


Pokoloruj mnie pod wrażeniem.
Mike Shlanta,

Prawdopodobnie powinieneś wspomnieć, że ostatni należy zapisać jako prgmG.
spaghetto


2

Oracle SQL 11.2, 104 118 bajtów

SELECT MAX(:1+:2-LEVEL+1)FROM DUAL WHERE(MOD(:1,:1+:2-LEVEL+1)+MOD(:2,:1+:2-LEVEL+1))*:1*:2=0 CONNECT BY LEVEL<=:1+:2;

Naprawiono dla wejścia 0


Nie działa poprawnie, jeśli jedno z wejść ma wartość zero.
Egor Skriptunoff,

To powinno cię uratowaćSELECT MAX(LEVEL)FROM DUAL WHERE MOD(:1,LEVEL)+MOD(:2,LEVEL)=0 CONNECT BY LEVEL<=:1+:2;
MickyT,

2

> <> , 12 + 3 = 15 bajtów

:?!\:}%
;n~/

Oczekuje, że liczby wejściowe będą obecne na stosie, więc +3 bajty dla -vflagi. Wypróbuj online!

Kolejna implementacja algorytmu euklidesowego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.