| | / | | 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