| | / | | d m k m = ≤ ,

Transkrypt

| | / | | d m k m = ≤ ,
Antoni M. Zajączkowski: Algorytmy i podstawy programowania – największy wspólny dzielnik
2 marca 2014
NAJWIĘKSZY WSPÓLNY DZIELNIK
DZIELNIK
Definicja 1. Liczba całkowita d jest dzielnikiem (divisor) liczby całkowitej m , wtedy i tylko
wtedy, gdy m jest całkowitą wielokrotnością d .
end Definicja
Inaczej mówiąc, dla pewnej liczby k ∈ ℤ spełnione jest równanie
m = d ⋅k .
Ponieważ ∀d ∈ ℤ : 0 = d ⋅ 0 , więc każda liczba całkowita jest dzielnikiem zera. Stąd wynika, że zero ma nieskończoną liczbę dzielników.
Nietrudno widzieć, że jeżeli d jest dzielnikiem liczby m , to jest też dzielnikiem liczby −m .
Z tego wnioskujemy, że dzielniki liczb m i −m są takie same. Poza tym, d ∈ ℤ jest
dzielnikiem m ∈ ℤ , wtedy i tylko wtedy, gdy −d jest dzielnikiem m . W związku z tym, dalsze rozważania można ograniczyć do nieujemnych liczb całkowitych.
Niech m > 0 i m = d ⋅ k dla pewnych d, k ∈ ℤ . Ponieważ d = m / k , więc
| d | = m / | k |≤ m ,
−m ≤ d ≤ m .
(1)
Pokazaliśmy, że wszystkie dzielniki liczby m > 0 należą do przedziału [−m, m ] .
Definicja 2. Wspólnym dzielnikiem (common divisor) liczb m i n nazywamy liczbę całkowitą, która jest jednocześnie dzielnikiem m i n .
end Definicja
Zauważmy, że liczby −1 i 1 są wspólnymi dzielnikami każdej liczby całkowitej.
Jeżeli m, n ∈ ℤ nie są równocześnie równe zeru, czyli prawdziwe jest zdanie
m ≠ 0 or n ≠ 0 ,
to zgodnie z (1) mogą mieć tylko skończoną liczbę wspólnych dzielników.
Definicja 3.
3 Największym
Największym wspólnym dzielnikiem (greatest common divisor) liczb m, n , z
których co najmniej jedna jest różna od zera, nazywamy największy z ich wspólnych dzielników. Oznaczamy go NWD(m, n ) , albo GCD(m, n ) .
end Definicja
Możemy teraz zająć się problemem obliczania NWD(m, n ) , czyli opracowaniem algorytmu wyznaczającego NWD(m, n ) .
Pierwszy algorytm znamy z matematyki elementarnej
1. Rozłożyć liczby | m | i | n | na czynniki pierwsze,
2. Znaleźć najwyższe potęgi czynników pierwszych, które są wspólnymi dzielnikami
| m | i | n |,
3. Znaleźć iloczyn tych potęg, co daje NWD(m, n ) .
Przykład 1.
1. Obliczmy NWD(135, 300) wg tego algorytmu.
Rozkład na czynniki pierwsze jest następujący:
135 = 1 ⋅ 3 ⋅ 3 ⋅ 3 ⋅ 5 , 300 = 1 ⋅ 2 ⋅ 2 ⋅ 3 ⋅ 5 ⋅ 5 .
Dzielnikami tych liczb są
135 : ±1, ±3, ±5, ±9, ±15, ±27, ±45, ±135 ,
300 : ±1, ±2, ±3, ±5, ±4, ±6, ±10, ±12, ±15, ±20, ±25, ±30, ±60, ±75, ±100, ±150, ±300 ,
a wspólnymi dzielnikami
1
Antoni M. Zajączkowski: Algorytmy i podstawy programowania – największy wspólny dzielnik
2 marca 2014
±3, ±5, ±15 i stąd NWD(135, 300) = 31 ⋅ 51 = 15 .
end Przykład
Zauważmy, że ten algorytm wyznaczania NWD wymaga rozkładu argumentów na czynniki pierwsze, co w przypadku dużych liczb znacznie wydłuża działanie algorytmu.
Zajmijmy się więc inną metodą, która nie wymaga kosztownego wyznaczania rozkładu na
czynniki pierwsze.
Na początku zauważmy, że jeżeli prawdziwe jest zdanie
m = 0 xor n = 0 ,
czyli dokładnie jedna z liczb jest równa zeru, to
NWD(m, n ) = Max(| m |,| n |) ,
natomiast, gdy obydwie te liczby są różne od zera, czyli spełniają warunek
m ≠ 0 and n ≠ 0 ,
to musi zachodzić nierówność
0 < NWD(m, n ) ≤ Min(| m |,| n |) .
Stąd wynika, że w tym ostatnim przypadku możemy wykonać obliczenia w pętli while,
zaczynając od
t = Min(| m |,| n |)
i sprawdzenia czy liczba ta dzieli bez reszty | m | i | n | . Jeżeli tak jest, to t = NWD(m, n )
i algorytm się kończy. W przeciwnym przypadku zmniejszamy t o 1 i przeprowadzamy test
dzielenia bez reszty liczb | m |,| n | . Ten krok powtarzamy tak długo, aż obydwie reszty
z dzielenia będą równe zeru. W najgorszym przypadku otrzymamy NWD(m, n ) = 1 , ponieważ 1 jest dzielnikiem każdej liczby całkowitej.
Opisany algorytm wyznaczania NWD nazywany bezpośrednim,
bezpośrednim a Sedgewick (1983) nazywa go siłowym (brute force).
1.. Ile razy wykonywana jest pętla while, w przypadku, gdy liczby m, n są
Zadanie 1
względnie pierwsze i żadna z nich nie jest równa zeru.
end Zadanie
Zadanie
Zadanie obliczeniowe 1. Napisać, uruchomić i przetestować program w języku Ada
wyznaczający NWD wg podanego algorytmu bezpośredniego. W przypadku, gdy dane wejściowe m, n ∈ ℤ są zerowe, należy ten przypadek wyróżnić komunikatem "NWD
nieokreslony" i nie wykonywać głównej ścieżki algorytmu. Oprócz NWD wyznaczyć liczbę
wykonań pętli.
end Zadanie obliczeniowe
Algorytm bezpośredni nie opiera się na kosztownym rozkładzie argumentów na czynniki
pierwsze, ale liczba powtórzeń pętli while w przypadku dużych wartości danych wejściowych jest wielka (patrz Zadanie 1).
1 Znacznie efektywniejszy jest algorytm Euklidesa
(Courant, Robbins, 1967: Ross, Wright, 2000), który oparty jest na następującym wyniku:
Twierdzenie 1 (Ross, Wright, 2000, 259). Jeżeli liczby m, n ∈ ℤ i n ≠ 0 , to wspólne dzielniki tych liczb są takie same jak wspólne dzielniki liczb n i m mod n , co zapisujemy w postaci
NWD(m, n ) = NWD(n, m mod n ) .
2
(2)
Antoni M. Zajączkowski: Algorytmy i podstawy programowania – największy wspólny dzielnik
2 marca 2014
Dowód: (Ross, Wright, 2000, 258).
end Twierdzenie
Przykład 2.
2. Zastosować to twierdzenie do wyznaczenia NWD następujących liczb (45,12)
i (135, 300) .
NWD(45,12) = NWD(12, 45 mod 12)
= NWD(12, 9) = NWD(9,12 mod 9)
= NWD(9, 3) = NWD(3, 9 mod 3)
= NWD(3, 0) = 3
NWD(135, 300) = NWD(300,135 mod 300)
= NWD(300,135) = NWD(135, 300 mod 135)
= NWD(135, 30) = NWD(30,135 mod 30)
= NWD(30,15) = NWD(15, 30 mod 15)
= NWD(15, 0) = 15
end Przykład
Przy implementacji komputerowej algorytmu Euklidesa warto zauważyć, że reszta z dzielenia spełnia nierówność
0 ≤ m mod n < n
oraz
NWD(m, n ) = NWD(n, m ) ,
NWD(m, n ) = NWD(| m |,| n |) .
W związku z tym, dogodnie jest zdefiniować zmienne pomocnicze
a = Max(| m |,| n |) ,
b = Min(| m |,| n |) ,
które spełniają warunki a ≥ b i NWD(m, n ) = NWD(a, b) .
Obliczenia wykonujemy przy pomocy pętli while, której test wejściowy jest relacją b ≠ 0 .
Wewnątrz pętli stosujemy podane twierdzenie, czyli NWD(a, b) = NWD(b, a mod b)
i odpowiednio wymieniamy zmienne. Powtarzamy ten proces tak długo, aż reszta z dzielenia stanie się równa zeru.
Nietrudno widzieć, że tak robiliśmy w ostatnim przykładzie, przy czym deklaracja zmiennych a, b wg podanych wzorów pozwala na pominięcie pierwszych dwóch operacji
wykonanych przy wyznaczaniu NWD(135, 300) .
To, że algorytm Euklidesa wyznacza NWD(m, n ) potwierdza
Twierdzenie 2.
2. Algorytm Euklidesa daje w wyniku NWD liczb całkowitych m, n takich, że
m ≠ 0 or n ≠ 0 .
Dowód: (Ross, Wright, 2000, 260).
end Twierdzenie
Liczbę przebiegów pętli while w tym algorytmie można oszacować stosując
Twierdzenie 3.
3. Dla danych liczb całkowitych m > n ≥ 0 algorytm Euklidesa wyznaczania
NWD(m, n ) wykonuje co najwyżej
2 log2 (m + n )
(3)
przebiegów pętli.
Dowód: (Ross, Wright, 2000, 260).
3
Antoni M. Zajączkowski: Algorytmy i podstawy programowania – największy wspólny dzielnik
2 marca 2014
end Twierdzenie
Zadanie obliczeniowe 2. Napisać, uruchomić i przetestować program w języku Ada
wyznaczający NWD wg podanego algorytmu Euklidesa. W przypadku, gdy dane wejściowe
m, n ∈ ℤ są zerowe, należy ten przypadek wyróżnić komunikatem "NWD nieokreslony"
i nie wykonywać głównej ścieżki algorytmu. Oprócz NWD wyznaczyć liczbę wykonań pętli
i porównać z oszacowaniem (3).
end Zadanie obliczeniowe
Literatura
Courant, R., Robbins, H. (1967). Co to jest matematyka. PWN, Warszawa (tłum. z ang.).
Ross, K.A, Wright, C.R.B. (2000). Matematyka dyskretna. PWN, Warszawa (tłum. z ang.).
Sedgewick, R. (1983). Algorithms. Addison-Wesley, Reading, Massachussets.
4