Realizacja algorytmu przez komputer Wstęp do informatyki Wykład 2 UniwersytetWrocławski 2012 Schemat logiczny komputera – urządzenia („układy”) wejścia i wyjścia: komunikacja ze światem – procesor: przetwarza informacje (wykonuje instrukcje), steruje pozostałymi elementami – pamięć: przechowuje informacje (dane i programy) – magistrale komunikacyjne: łączą pozostałe elementy Maszyna RAM Tydzień temu: – opis algorytmu w języku zrozumiałym dla człowieka: schemat blokowy, pseudokod. Dziś: – schemat logiczny komputera; – zapis algorytmu w formie umożliwiającej wykonanie go przez komputer; Maszyna RAM – taśma wejściowa: ciąg liczb całkowitych – taśma wyjściowa : ciąg liczb całkowitych, wypisywanych przez program – procesor: wykonuje instrukcje – pamięć: komórki 0, 1, 2, 3,…; przechowują liczby całkowite • Komórka 0: akumulator – program: ciąg instrukcji do wykonania – licznik rozkazów: wskazuje na instrukcję, która aktualnie powinna być wykonana RAM: szczegóły taśma wejściowa • Pamięć: nieskończona liczba komórek etykietowanych 0, 1, 2,.. • Komórka 0 nazywana rejestrem lub akumulatorem • Każda komórka może przechowywać dowolną liczbę całkowitą • Taśma wejściowa i wyjściowa to urządzenia sekwencyjne: – taśma wejściowa: dane dla programu (wejście) – taśma wyjściowa: wyniki programu (wyjście) – Urządzenie sekwencyjne: program „przemieszcza” się tylko w jednym kierunku, zawsze do następnej pozycji; każdy element czytany tylko jeden raz; taśma wyjściowa 1 Wykonanie programu RAM: cykl główny procesora • Pobierz instrukcję do wykonania – wskazywaną przez licznik rozkazów • Pobierz argumenty instrukcji do wykonania • Wykonaj instrukcję • Uaktualnij licznik rozkazów (o ile nie został zmieniny przez instrukcję…) Powtarzaj cykl główny procesora aż do momentu gdy: • Licznik rozkazów nie wskazuje na żadną instrukcję LUB • Wykonana została instrukcja HALT RAM: instrukcje Składnia: <etykieta> <instrukcja> <argument> Instrukcje wejścia/wyjścia: Read Czyta kolejną liczbę z taśmy wejściowej Write Wypisuje liczbę na końcu taśmy wyjściowej RAM: instrukcje cd Instrukcje arytmetyczne: Add Sub Dodaj zawartość akumulatora i argument Od akumulatora odejmij argument Mult Pomnóż zawartość akumulatora przez argument Podziel zawartość akumulatora przez argument (wynik zakrąglony w dół) Przesłanie do / z akumulatora: Load Prześlij do akumulatora Div Store Prześlij zawartość akumulatora do innej komórki Rezultat jest zawsze umieszczany w akumulatorze. RAM: instrukcje cd Halt: zakończ działanie programu Uwaga: • halt nie jest konieczne, • Jeśli licznik rozkazów wskazuje na pozycję nie zawierającą żadnej instrukcji, program również się zatrzymuje. RAM: argumenty Argument Znaczenie 〈liczba〉 zawartość komórki o numerze liczba wartość liczba adresownie pośrednie: zawartość komórki, której numer znajduje się w komórce o numerze liczba etykieta instrukcji = 〈liczba〉 ^ 〈liczba〉 〈etykieta〉 2 Argumenty instrukcji: przykład • load 5: zawartość komórki numer 5 pobierz (skopiuj) do akumulatora • load =5: umieść liczbę 5 w akumulatorze • load ^5: do akumulatora pobierz (skopiuj) zawartość komórki, której numer znajduje się w komórce 5 Argumenty instrukcji: przykład div 5: podziel zawartość akumulatora przez zawartość komórki numer 5 div =5: podziel zawartość akumulatora przez liczbę 5 div ^5: podziel zawartość akumulatora przez zawartość komórki, której numer znajduje się w komórce 5 WYNIK jest zawsze umieszczany w akumulatorze! Argumenty instrukcji: przykład Komórka 0 1 2 3 4 5 6 7 Wartość 90 15 Instrukcja Nowa wartość komórki 0 div 5 30 (90/3) div =5 18 (90/5) div ^5 6 (90/15) Translacja na kod RAM: Read 1 Read 2 Load 1 Add 2 Store 3 Write 3 Halt Start Read a, b c ← a+b write c 3 Stop Skojarzenie z komórkami pamięci: 1–a 2–b 3–c Instrukcje RAM: skoki Jump Skok bezwarunkowy Jzero Skok pod warunkiem, że w akumulatorze znajduje się zero Jgtz Kod RAM: przykład Wejście: a, b – liczby Wyjście: a + b Skok pod warunkiem, że w akumulatorze znajduje się liczba większa od zera RAM przykład: maksimum z dwóch liczb Wejście: a, b – liczby Wyjście: maksimum liczb a, b Czytaj a, b no Wypisz b Argument: etykieta instrukcji Etykieta: napis umieszczony z lewej strony instrukcji (nie jest wymagana). a-b>0 yes Wypisz a et1 Skojarzenie: 1–a 2–b Ćwiczenie. uzupełnij powyższy schemat o bloki Start i Stop. et1 READ 1 READ 2 LOAD 1 SUB 2 JGTZ et1 WRITE 2 HALT WRITE 1 HALT 3 Translacja schematu blokowego na kod RAM • Skojarz zmienne z komórkami pamięci • Translacja każdego bloku schematu blokowego osobno! Zaznacz instrukcje odpowiadające każdemu blokowi! • Przekształć warunki sprawdzane w schemacie blokowym do jednej z postaci 〈wyrazenie〉 = 0 〈wyrazenie〉 > 0 Używaj skoków aby zmienić odpowiednio licznik rozkazów (przejść do odpowiedniego fragmentu programu). Schemat blokowy ⇒ RAM tak nie et2 <expr> = 0 … … et3 … • oblicz <expr>, wynik masz w akumulatorze; • wykonaj skok warunkowy: jzero et1 • Kod odpowiadający „nie” podaj pod instrukcją skoku et1 … <expr> … jzero et1 et2 … … jump et3 et1 … … jump et3 et3 … Schemat blokowy ⇒ kod RAM x ← <expr1> + <expr2> Skojarzona z komórką j • oblicz <expr1>, zachowaj w pewnej komórce i • oblicz <expr2>, wynik masz w akumulatorze! • dodaj <expr1> do <expr2>: add i • zachowaj wynik w komórce j: store j Suma ciągu liczb Wejście: ciąg liczb zakończony zerem! Wyjście: suma wszystkich liczb w ciągu Start s←0 loop Read a nie s←s+a a=0 etkon tak Write s Stop Suma ciągu liczb, cd Suma ciągu liczb – złożoność czasowa Start s←0 loop nie s←s+a Read a a=0 tak etkon Write s Skojarzenia komórek i zmiennych: 1–a 2–s Stop load =0 store 2 loop read 1 load 1 JZERO etkon load 2 add 1 store 2 jump loop etkon write 2 Rozmiar danych: n – liczba elementów do zsumowania (bez ostatniego zera) „Złożoność” schematu blokowego: 1 + 3n + 3 = 3n + 4 „Złożoność” programu w kodzie RAM: 2 + 7n + 4 = 7n + 6 „Która złożoność poprawna”? 4 Złożoność asymptotyczna Notacja „dużego O”: • ignorujemy stałe zależne od zapisu algorytmu / modelu obliczeń; • np., 10n, n+7, 112n są „podobne” (funkcje liniowe); • Lecz 100n and 2n2 istotnie się różnią! Pyt.: Która z nich jest „większa”? Odp.: 2n2 Pyt.: Dlaczego? A: Szybciej rośnie! Złożoność asymptotyczna - intuicja f(n) = O(g(n)) wtw g(n) rośnie co najmniej tak samo szybko jak f(n) gdy n→∝ Złożoność asymptotyczna – przykłady n2 / 1000 ≠ O(n), gdyż dla każdego c>0 mamy: n2 / 1000 > c⋅n dla nieskończenie wielu n. W szczególności, nierówność n2 / 1000 > c⋅n zachodzi dla każdego n spełniającego n > 1000⋅max(c,1). Złożoność asymptotyczna Notacja „dużego O” formalnie: f(n) = O(g(n)) wtedy i tylko wtedy gdy (wtw) istnieje stała c>0 i liczba naturalna m>0 takie, że f(n)≤c⋅g(n) dla każdego n>m. Złożoność asymptotyczna – przykłady 100⋅n = O(n2), gdyż 100⋅n ≤ 100 ⋅ n2 dla każdego n>0. 55⋅n2+100n-10 = O(n2), gdyż 55⋅n2+100n-10 ≤ 57⋅n2 dla każdego n>60. n2 =O(2n), gdyż n2 ≤ 2n dla każdego n>5. [jak to pokazać?] Złożoność asymptotyczna – przykłady 100⋅n = O(n) 100⋅n = O(n2) n2 / 1000 ≠ O(n) 77⋅n+333 = O(n) 55⋅n2+100n-10 = O(n2) 55⋅n2+100n-10 = O(n3) 55⋅n2+100n-10 ≠ O(n) n2 =O(2n) 2n≠ O(n2) 5 Suma ciągu liczb – złożoność czasowa Sortowanie przez zliczanie Rozmiar danych: n – liczba elementów do zsumowania (bez ostatniego zera) „Złożoność” schematu blokowego: 1 + 3n + 3 = 3n + 4 „Złożoność” programu w kodzie RAM: Problem Wejście: n – liczba naturalna; a1,a2,...,an – ciąg liczb naturalnych z przedziału [0,9] Wyjście: elementy a1,a2,...,an wypisane w porządku niemalejącym 2 + 7n + 4 = 7n + 6 Przykład Wejście: 11; 0, 7, 9, 9, 2, 1, 6, 7, 6, 5, 5 Wyjście: 0, 1, 2, 5, 5, 6, 6, 7, 7, 9, 9 Złożoność asymptotyczna: O( n ) Sortowanie przez zliczanie Algorytm •Nadaj licznikom K0,…,K9 wartość zero. •Wczytaj n •Dla i=1,2,…,n powtarzaj: •Wczytaj a •Ka ← Ka+1 •Dla i=0, 1, 2, …,9 powtarzaj: •Powtórz Ki razy: •Wypisz i Sortowanie przez zliczanie Zamiast Ki używamy zmiennej złożonej K o elementach K[0],…,K[9]: •elementy K[0],…,K[9] tego samego typu; •indeksowane kolejnymi liczbami naturalnymi K – tablica (p. tablice w Ansi C) Implementacja •K[0],…,K[9] – sąsiednie komórki pamięci licznik: „zlicza” liczbę wystąpień pewnego zdarzenia Sortowanie przez zliczanie Wstaw 0 do K[0]..K[9] wczytaj n i←n 3 1 2 Assign 0 to C[15]..C[24] read C2 C3 ← C2 3 tak Uwaga: komórkę Ci będziemy też oznaczać przez C[i] i=0? nie wczytaj a Sortowanie przez zliczanie Skojarzenia: K[0]..K[9]: komórki 15..24 n : C2 i : C3 a : C4 j : C5 j ←0 4 2 Uwaga: komórkę Ci będziemy też oznaczać przez C[i] yes C3 = 0 ? no 7 read C4 5 Skojarzenia: K[0]..K[9]: C[15]..C[24] n : C2 i : C3 a : C4 j : C5 1 4 K[a] ← K[a]+1 tak 7 j>9? C[C4+15] ← C[C4+15]+1 8 C5 > 9 ? 8 yes nie 6 C5 ←0 5 i ← i-1 no Powtórz K[j] razy: wypisz j 6 C3 ← C3-1 Repeat C[C5+15] times: write C5 9 9 j← j+1 Stop 10 C5 ← C5 + 1 The end 10 6 Sortowanie przez zliczanie Assign 0 to C[15]..C[24] C6 ← 24 1a 1b 1 yes 2 C6<15 no C[C6] ← 0 1c C6 ← C6-1 1d load store L1b: load sub jgtz load store load sub store jump =24 6 =15 6 l2 =0 ^6 6 =1 6 L1b Sortowanie przez zliczanie #1a #1b C[C4+15] ← C[C4+15]+1 #1c #1d Sortowanie przez zliczanie 9 Repeat C[C5+15] times: write C5 load add store load store L9b: load jgtz jump L9c: write load sub store jump 5 =15 7 ^7 8 8 L9c L10 5 8 =1 8 L9b C7 ← C5+15 C8 ← C[C7] #9a 9b no #9b Write C5 9c C8 ← C8-1 9d 10 #9c #9d Sortowanie przez zliczanie – złożoność Rozmiar danych: n? n+k? Pamięć: proporcjonalna do k, czyli O( k ) Czas: proporcjonalny do n+k, czyli O( n+k ) : • gdy n > k: O( n + k ) = O( n ) • gdy n ≤ k: O( n + k ) = O( k ) 4 #5 =15 7 ^7 =1 ^7 Sortowanie przez zliczanie ogólniej Problem Wejście: n – liczba naturalna; a1,a2,...,an – ciąg liczb całkowitych z zakresu [0,k], k<n. 9a C8>0 yes 5 load add store load add store Wyjście: elementy ciągu a1,a2,...,an wypisane w porządku niemalejących Rozwiązanie Zamiast tablicy rozmiaru 10, użyj tablicy rozmiaru k. Sortowanie przez zliczanie – złożoność Czas: proporcjonalny do n+k, czyli O( n+k ) : gdy n > k: O( n + k ) = O( n ) gdy n ≤ k: O( n + k ) = O( k ) Uwaga Jeśli k>>n: • potrzebujemy większej pamięci niż długość ciągu! • czas obliczeń proporcjonalny do k, czyli znacznie większy od n (czy taki algorytm jest „praktyczny”?). 7 Podsumowanie 1. Maszyna RAM – model komputera: • „Zmienna” liczbowa – komórka w pamięci • Operacje arytmetyczne – wykonaj operację na akumulatorze i (ewentualnie) zawartości innej komórki • Cykl główny procesora • Pętle – skoki – licznik rozkazów. 2. Adresowanie pośrednie i jego zastosowania! 3. Notacja asymptotyczna w szacowaniu złożoności 4. Problem sortowania; sortowanie przez zliczanie: jak działa? kiedy przydatne? 8