Algorytm Euklidesa

Algorytm Euklidesa
Ilustracja
Euclid’s algorithm Book VII Proposition 2 3
Rodzaj

Wyznaczanie największego wspólnego dzielnika dwóch liczb

Struktura danych

Dwie liczby naturalne

Złożoność
Czasowa

O (   log 2 ( m + n )   ) {\displaystyle O(\ \log _{2}(m+n)\ )}

Pamięciowa

O ( 1 ) {\displaystyle O(1)}

Algorytm Euklidesa – algorytm wyznaczania największego wspólnego dzielnika dwóch liczb[1]. Został opisany przez greckiego matematyka, Euklidesa w jego dziele „Elementy”, w księgach siódmej oraz dziesiątej[2].

Pierwsze wzmianki na temat tego algorytmu pojawiły się w dziele Euklidesa zatytułowanym „Elementy”, około trzysetnego roku przed naszą erą, co sprawia, że jest jednym z najstarszych, wciąż używanych algorytmów numerycznych. Pierwsza wersja algorytmu została opisana tylko dla liczb naturalnych. W XIX wieku powstały odmiany algorytmu dla liczb całkowitych Gaussa oraz wielomianów z jedną niewiadomą. Doprowadziło to do powstania współczesnych pojęć algebry abstrakcyjnej, takich jak dziedzina Euklidesa. W późniejszych czasach opracowano odmiany algorytmu dla innych struktur matematycznych, jak węzły czy wielomiany z wieloma niewiadomymi.

Istnieje wiele teoretycznych i praktycznych zastosowań algorytmu. Może on zostać wykorzystany do generowania rytmów muzycznych, stosowanych jako ostinato w muzyce[3]. Jest wykorzystywany w algorytmie RSA. Algorytm Euklidesa używany jest też do rozwiązywania równań diofantycznych, na przykład do znajdowania liczb spełniających zadany układ kongruencji (chińskie twierdzenie o resztach) czy znajdowania liczb odwrotnych w ciele skończonym. Może być także stosowany do generowania ułamków łańcuchowych w metodzie Sturma do obliczania pierwiastków rzeczywistych wielomianu. Wykorzystywany jest również w kilku współczesnych algorytmach do faktoryzacji liczb całkowitych.

Jeżeli algorytm zostanie zaimplementowany poprzez obliczanie reszt z dzielenia, a nie odejmowanie, to jest wydajny dla dużych liczb: nigdy nie wymaga więcej dzieleń niż liczba cyfr (w systemie dziesiętnym) mniejszej liczby pomnożona przez 5. Zostało to udowodnione przez Gabriela Lamé w 1844 i uważane jest za pierwszy przypadek analizy złożoności obliczeniowej algorytmu. Sposoby zwiększenia wydajności algorytmów zostały opracowane w XX wieku.

Największym wspólnym dzielnikiem dwóch liczb jest największa z liczb, która dzieli obie te liczby bez reszty. Algorytm Euklidesa opiera się na założeniu, że największy wspólny dzielnik dwóch liczb nie zmienia się, jeżeli od większej liczby odejmujemy mniejszą. Dla liczb całkowitych k, m oraz n załóżmy, że k jest wspólnym czynnikiem liczb A oraz B; załóżmy też, że A = ( n k ) , {\displaystyle A=(n*k),} B = ( m k ) {\displaystyle B=(m*k)} oraz A > B . {\displaystyle A>B.} Możemy teraz dokonać działania A B = ( n m ) k , {\displaystyle A-B=(n-m)*k,} wiemy więc, że k jest także wspólnym czynnikiem różnicy tych liczb.

Opis algorytmu

Najprostsza wersja algorytmu rozpoczyna się od wybrania dwóch liczb naturalnych, dla których należy wyznaczyć największy wspólny dzielnik. Następnie z tych dwóch liczb tworzymy nową parę: pierwszą z liczb jest liczba mniejsza, natomiast drugą jest różnica liczby większej i mniejszej. Proces ten jest powtarzany aż obie liczby będą sobie równe – wartość tych liczb to największy wspólny dzielnik wszystkich par liczb wcześniej wyznaczonych. Wadą tej wersji algorytmu jest duża liczba operacji odejmowania, które należy wykonać w przypadku, gdy różnica pomiędzy liczbami z pary jest znacząca.

Operacja odejmowania mniejszej liczby od większej może zostać zastąpiona przez wyznaczanie reszty z dzielenia[4]. W tej wersji nowa para liczb składa się z mniejszej liczby oraz reszty z dzielenia większej przez mniejszą. Algorytm kończy się w momencie, w którym jedna z liczb jest równa zero – druga jest wtedy największym wspólnym dzielnikiem.

Przykład – wersja z odejmowaniem

Załóżmy, że chcemy znaleźć największy wspólny dzielnik liczb 1989 oraz 867. Jeżeli od większej liczby odejmiemy liczbę mniejszą, wartość największego wspólnego dzielnika nie ulegnie zmianie. Ponieważ 1989 – 867 = 1122, nowa para liczb wygląda następująco:

1122, 867

Ponownie odejmujemy mniejszą liczbę od większej 1122 – 867 = 255, tworząc w ten sposób kolejną parę:

255, 867

867 nie jest już mniejszą liczbą. Stosując ten sam sposób, ponownie zmniejszamy wartość większej liczby o wartość mniejszej: 867 – 255 = 612, nowa para liczb to:

255, 612

Pierwsza liczba, 255, jest wciąż mniejsza, ponownie więc odejmujemy 255 od liczby większej: 612 – 255 = 357, więc kolejna para liczb to:

255, 357

357 – 255 = 102, kolejna para to:

255, 102

Teraz widać, że 255 jest większą liczbą, odejmujemy więc od niej 102, co daje nam parę:

153, 102

Odjęcie 102 od 153 tworzy nam kolejną parę:

51, 102.

Teraz odejmujemy 51 od 102, co daje nam:

51, 51

Ponieważ obie liczby są sobie równe, kolejne odejmowanie da nam zero. Oznacza to, że największym wspólnym dzielnikiem liczb 1989 i 867 jest liczba 51.

Algorytm wykorzystujący funkcję modulo

Algorytm wykorzystujący funkcję modulo to druga równoważna implementacja algorytmu Euklidesa[4]. Poniżej przedstawiono wersję obliczania NWD liczb a i b wykorzystującą operację reszty z dzielenia (modulo):

  1. oblicz c jako resztę z dzielenia a przez b
  2. zastąp a liczbą b, następnie b liczbą c
  3. jeżeli wartość b wynosi 0, to a jest szukaną wartością NWD, w przeciwnym wypadku przejdź do kroku 1

Pseudokod

podprogram NWD(a, b)
    dopóki b ≠ 0
        c := reszta z dzielenia a przez b
        a := b
        b := c
    zwróć a

Dowód poprawności

Lemat: N W D ( a , b ) = N W D ( b , a   m o d   b ) {\displaystyle NWD(a,b)=NWD(b,a\ mod\ b)}

Aby to wykazać, należy udowodnić, że wspólny podzielnik liczb a {\displaystyle a} i b {\displaystyle b} jest również podzielnikiem liczby a   m o d   b {\displaystyle a\ mod\ b}
Przyjmijmy:
d = N W D ( a , b ) a = s d ,   b = t d {\displaystyle d=NWD(a,b)\Rightarrow a=sd,\ b=td}
r = a   m o d   b a = p b + r {\displaystyle r=a\ mod\ b\Rightarrow a=pb+r}
gdzie s , t , p {\displaystyle s,t,p} są liczbami całkowitymi.
Wtedy:
r = a p b = s d p t d = d ( s p t ) {\displaystyle r=a-pb=sd-ptd=d(s-pt)}
zatem d {\displaystyle d} jest również podzielnikiem r {\displaystyle r}

Z lematu wynika przez indukcję, że jeśli algorytm się zakończy, to da poprawny wynik. Pozostaje udowodnić, że się zakończy. Wystarczy w tym celu zauważyć, że 0 a   m o d   b b 1 , {\displaystyle 0\leqslant a\ mod\ b\leqslant b-1,} więc w każdym kroku algorytmu wartość b {\displaystyle b} zmniejsza się przynajmniej o 1. Ponieważ nie może nigdy być ujemna, algorytm musi się zakończyć.

Złożoność czasowa

Dla dowolnych liczb m > n 0 {\displaystyle m>n\geqslant 0} algorytm Euklidesa zwraca wartość NWD(m, n) po co najwyżej 2 log 2   ( m + n ) {\displaystyle 2\cdot \log _{2}\ (m+n)} przebiegach pętli.

Dowód

  • Lemat: Jeśli a b {\displaystyle a\geqslant b} to
b + a mod b < 2 3 ( a + b ) {\displaystyle b+a{\bmod {b}}<{\tfrac {2}{3}}\cdot (a+b)}
(1)
(1) jest równoważne b + 3 ( a mod b ) < 2 a {\displaystyle b+3\cdot (a{\bmod {b}})<2a}
Podstawiając
a = b ( a div b ) + a mod b {\displaystyle a=b\cdot (a\operatorname {div} b)+a{\bmod {b}}}
otrzymuje się:
b + a mod b < 2 b ( a div b ) {\displaystyle b+a{\bmod {b}}<2b\cdot (a\operatorname {div} b)}
i ponieważ a b {\displaystyle a\geqslant b} to a div b 1 , {\displaystyle a\operatorname {div} b\geqslant 1,} oraz ponadto z własności modulo a mod   b b {\displaystyle a{\bmod {\ }}b\leqslant b} otrzymujemy:
b + a mod b < 2 b 2 b ( a div b ) {\displaystyle b+a{\bmod {b}}<2b\leqslant 2b\cdot (a\operatorname {div} b)}
  • Przy pierwszej iteracji mamy a + b = m + n , {\displaystyle a+b=m+n,} po k-tym przebiegu pętli:
a + b ( 2 3 ) k ( m + n ) {\displaystyle a+b\leqslant \left({\tfrac {2}{3}}\right)^{k}\cdot (m+n)}
  • Ponieważ a + b 1 , {\displaystyle a+b\geqslant 1,} po ostatnim, l-tym przebiegu pętli będzie:
1 ( 2 3 ) l ( m + n ) {\displaystyle 1\leqslant \left({\tfrac {2}{3}}\right)^{l}\cdot (m+n)}
( 3 2 ) l m + n {\displaystyle \left({\tfrac {3}{2}}\right)^{l}\leqslant m+n}
log 2   ( m   +   n ) l log 2   3 2 > 1 2 l {\displaystyle \log _{2}\ (m\ +\ n)\geqslant l\cdot \log _{2}\ {\tfrac {3}{2}}>{\tfrac {1}{2}}\cdot l}
l   <   2 log 2   ( m   +   n ) {\displaystyle l\ <\ 2\cdot \log _{2}\ (m\ +\ n)}

Największej liczby kroków algorytmu wymagają takie liczby m i n, które są kolejnymi elementami ciągu Fibonacciego.

Rozszerzony algorytm Euklidesa

Jeśli przechowywana będzie informacja o kolejnych ilorazach, to będzie też można wyznaczyć liczby całkowite w równaniu a p + b q = NWD ( a , b ) . {\displaystyle a\cdot p+b\cdot q=\operatorname {NWD} (a,b).} Ta metoda nazywana jest rozszerzonym algorytmem Euklidesa.

Na przykład dla liczb 174 i 18 w algorytmie Euklidesa uzyskuje się wyniki pośrednie:

174 / 18 = 9  i reszta  12 {\displaystyle 174/18=9{\mbox{ i reszta }}12}
18 / 12 = 1  i reszta  6 {\displaystyle 18/12=1{\mbox{ i reszta }}6}
12 / 6 = 2  i reszta  0 {\displaystyle 12/6=2{\mbox{ i reszta }}0}

lub przepisując wszystkie równości w taki sposób, by w pierwszej z nich po prawej stronie występowała tylko suma pewnych wielokrotności liczb 174 i 18:

12 = 1 174 + ( 9 ) 18 {\displaystyle 12=1\cdot 174+(-9)\cdot 18}
6 = 1 18 + ( 1 ) 12 {\displaystyle 6=1\cdot 18+(-1)\cdot 12}
0 = 1 12 + ( 2 ) 6 {\displaystyle 0=1\cdot 12+(-2)\cdot 6}

Należy zauważyć, że w pierwszej równości po prawej stronie występuje kombinacja liniowa liczb 174 i 18, podobnie jak w równaniu a p + b q = NWD ( a , b ) . {\displaystyle a\cdot p+b\cdot q=\operatorname {NWD} (a,b).} W następnych równościach po prawej stronie jest zawsze kombinacja liniowa liczb 174, 18 lub liczb, które wystąpiły po lewej stronie we wcześniejszych równościach.

Kluczowa dla rozszerzonego algorytmu Euklidesa staje się możliwość stopniowego zastępowania tych liczb przez kombinacje liniowe liczb wejściowych aż do otrzymania równości:

NWD ( a , b ) = kombinacja liniowa liczb a, b {\displaystyle \operatorname {NWD} (a,b)={\mbox{kombinacja liniowa liczb a, b}}}

np.

6 = 1 18 + ( 1 ) 12 = 1 18 + ( 1 ) ( 1 174 + ( 9 ) 18 ) = ( 1 ) 174 + 10 18 {\displaystyle 6=1\cdot 18+(-1)\cdot 12=1\cdot 18+(-1)\cdot (1\cdot 174+(-9)\cdot 18)=(-1)\cdot 174+10\cdot 18}

Pseudokod

podprogram NWD(a, b)
    x := 1
    y := 0
    r := 0
    s := 1

    dopóki b ≠ 0
        c := reszta z dzielenia a przez b
        q := część całkowita z dzielenia a przez b
        a := b
        b := c

        r' = r
        s' = s
        r = x - q · r
        s = y - q · s
        x = r'
        y = s'

    zwróć a, x, y

Niezmiennikami pętli są wielkości x · a0 + y · b0 = a oraz r · a0 + s · b0 = b, dzięki czemu NWD(a0, b0) = x · a0 + y · b0.

Zobacz też

Przypisy

  1. algorytm Euklidesa, [w:] Encyklopedia PWN [dostęp 2021-10-02] .
  2. Thomas L. Heath: The Thirteen Books of Euclid’s Elements 2nd edition. (ang.).
  3. Godfried Toussaint: The Euclidean Algorithm Generates Traditional Musical Rhythms. [dostęp 2012-08-10]. (ang.).
  4. a b Ronald L. Graham, Donald E. Knuth, Oren Patashnik: Matematyka konkretna. PWN, 2001, s. 124. ISBN 83-01-12124-6.

Linki zewnętrzne

  • Eric W.E.W. Weisstein Eric W.E.W., Euclidean Algorithm, [w:] MathWorld, Wolfram Research [dostęp 2020-12-12]  (ang.).
  • publikacja w otwartym dostępie – możesz ją przeczytać Euclidean algorithm (ang.), Encyclopedia of Mathematics, encyclopediaofmath.org [dostęp 2024-02-02].
  • p
  • d
  • e
ogólne typy liczb
relacje
podzielność
zdefiniowane podzielnością
działania
liczby pierwsze
podstawy
testy pierwszości
sita
faktoryzacja
hipotezy
równania
diofantyczne
liniowe
kwadratowe
wyższych stopni
układy równań
powiązane zagadnienia
twierdzenia
arytmetyki modularnej
inne zagadnienia
twierdzenia limitacyjne
  • p
  • d
  • e
typy
według
stopnia
inne
powiązane pojęcia
algorytmy
twierdzenia algebraiczne
o wielomianach
rzeczywistych dowolnych
zespolonych dowolnych
innych typów
równania algebraiczne
krzywe tworzące wykresy
twierdzenia analityczne
uogólnienia
powiązane działy
matematyki
arytmetyka
algebra
geometria
analiza
uczeni

Encyklopedia internetowa:
  • PWN: 3899056
  • Britannica: topic/Euclidean-algorithm
  • БРЭ: 1973631
  • NE.se: euklides-algoritm
  • SNL: evklidsk_algoritme
  • DSDE: Euklids_algoritme
  • identyfikator w Hrvatska enciklopedija: 18595