Z pogranicza informatyki esejów i ćwiczeń kilka
Transkrypt
Z pogranicza informatyki esejów i ćwiczeń kilka
Z pogranicza informatyki esejów i ćwiczeń kilka Piotr Fulmański1 30 listopada 2007 1 E-mail: [email protected] 2 Spis treści c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Spis treści Spis treści 3 Przedmowa 5 1 Zbuduj sobie HDA 1.1 Układy cyfrowe . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Postawienie problemu i jego analiza . . . . . . . . . . . . . . 1.3 Identyfikacja sygnałów wejściowych i wyjściowych . . . . . . 1.4 Troszkę bardziej formalny opis działania układu sterującego 1.5 Podstawowe bramki . . . . . . . . . . . . . . . . . . . . . . 1.6 Tworzenie schematu układu . . . . . . . . . . . . . . . . . . 1.6.1 Etap I . . . . . . . . . . . . . . . . . . . . . . . . . . 1.6.2 Etap II . . . . . . . . . . . . . . . . . . . . . . . . . 1.7 Minimalizacja układu poprzez minimalizację wyrażenia logicznego . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.8 Mnemotechniczne sposoby minimalizacji wyrażeń logicznych 1.9 Kod Gray’a . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.10 Tablice Karnaugha . . . . . . . . . . . . . . . . . . . . . . . 2 Dwie bramki to już układ 2.1 Komparator jednobitowy . . . . 2.2 Sumator jednobitowy . . . . . . . 2.3 Dekoder adresowy . . . . . . . . 2.4 Przerzutniki . . . . . . . . . . . . 2.4.1 Przerzutniki typu R-S . . 2.4.2 Hazard . . . . . . . . . . 2.4.3 Synchroniczny przerzutnik 2.4.4 Przerzutnik typu D . . . . 2.4.5 Przerzutnik typu J-K . . . . . . . . . . . . . . . . . . . . typu . . . . . . . . . . . . . . . . . . . . . . . . R-S . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 7 8 8 9 12 14 14 15 . . . . 15 15 21 22 . . . . . . . . . 27 27 28 30 32 32 33 35 36 36 4 Przedmowa 2.5 2.6 2.7 Rejestr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Pamięć . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Licznik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3 Dlaczego 2+2=5? 3.1 Dlaczego? . . . . 3.2 Doświadczenie 1 3.3 Doświadczenie 2 3.4 Wnioski . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 41 42 45 49 4 Obliczenia numeryczne 53 4.1 O strukturze pamięci . . . . . . . . . . . . . . . . . . . . . . . 53 4.2 O tym co, jak i w czym liczymy . . . . . . . . . . . . . . . . . 55 5 Architektury równoległe 5.1 Podział . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Klasyfikacja architektur równoległych według Flynna . 5.2.1 SISD . . . . . . . . . . . . . . . . . . . . . . . . 5.2.2 SIMD . . . . . . . . . . . . . . . . . . . . . . . 5.2.3 MIMD . . . . . . . . . . . . . . . . . . . . . . . 5.3 Klasyfikacja architektur równoległych według Duncana 5.3.1 Wektorowe . . . . . . . . . . . . . . . . . . . . 5.3.2 SIMD . . . . . . . . . . . . . . . . . . . . . . . 5.3.3 Systoliczne . . . . . . . . . . . . . . . . . . . . 5.3.4 MIMD z pamięcią rozproszoną . . . . . . . . . 5.3.5 MIMD z pamięcią wspólną . . . . . . . . . . . 5.3.6 MIMD/SIMD . . . . . . . . . . . . . . . . . . . 5.3.7 Przepływ danych . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 59 59 60 60 61 61 62 62 63 63 63 63 63 6 Errata 65 6.1 Poprawki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 6.2 Uzupełnienie literatury . . . . . . . . . . . . . . . . . . . . . . 67 Bibliografia 69 c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Przedmowa Pisanie jest jedyną sztuką, której musimy się nauczyć pisząc. Autor anonimowy Trudno powiedzić czym jest niniejszy skrypt1 . Z pewnością nie jest to podręcznik do Wstępu do informatyki, gdyż takowy został już przez autorów wydany. Nie jest to także skrypt do ćwiczeń, choć niektóre rozdziały mogą to sugerować. Najprostszym określeniem będzie: zbiór różności. Tak więc znajdziemy tutaj zarówno materiał ćwiczeniowy służący pogłębianiu informacji zawartych we „Wstęp do informatyki. Podręcznik” jak i rozdziały mogące stanowić w przyszłości II tom wspomnianego podręcznika. II tomu jednak nie będzie. Przyjęta w niniejszym skrypcie formuła daje bowiem większą swobodę w doborze tematów. Ponieważ z założenia jest to zbiór różności tak więc nie jest konieczne przestrzeganie ciągłości wywodów i stopniowanie trudności materiłu. Zasadniczo każdy rozdział jest niezależny od pozostałych i nie zakłada się, że wszystko zostanie tutaj wyjaśnione. Jak sam tytuł mówi jest to bowiem zbiór kilku ćwiczeń i wykładów (czyli esejów, bo wykład to nic innego jak opowiadanie na jakiś temat) w jakiś sposób, mocniejszy lub luźniejszy, związanych z informatyką. Piotr Fulmański, Ścibór Sobieski 1 W obecnej postaci nie jest to nawet skrypt. Jest to zbiór notatek jakie i tak dla siebie sporządzamy przygotowywując zajęcia. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 6 SPIS TREŚCI c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Rozdział 1 Zbuduj sobie HDA Wykład to przenoszenie wiadomości z notatek wykładowcy do notatek ucznia – z pominięciem mózgów ich obu. Pokolenia uczniów 1.1 Układy cyfrowe Układy cyfrowe, nazywane także układami logicznymi są strukturami przetwarzającymi sygnały dwuwartościowe. Działanie tych układów opisane jest za pomocą algebry sygnałów, która należy do rodziny algebr Boole’a. Elementy zbioru wartości, którymi algebra ta operuje, zwykło się oznaczać przez 0 i 1. Wartości te odpowiadają poziomom napięcia wytwarzanego przez układy elektroniczne. W tak zwanej logice dodatniej napięciu wysokiemu odpowiada wartość sygnału 1, natomiast niskiemu – wartość 0; w logice ujemnej mamy do czynienia z sytucją odwrotną. W tym rozdziale skupimy się na jednym z rodzajów układów logicznych jakim są układy kombinacyjne. Długo zastanawialiśmy się jak podejść do tego tematu aby łagodnie wprowadzić czytelnika w niezwykły świat układów cyfrowych. Wybawieniem okazała się książka Cezarego Zielińskiego [5] właśnie z uwagi na czytelne i zrozumiałe prowadzenie wywodów. Z niej zaczerpnęliśmy pomysł na prosty automat. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 8 Zbuduj sobie HDA produkt bułka bułka + parówka bułka + parówka + musztarda cena 2 3 5 Tablica 1.1. Funkcjonalność HDA Rys. 1.1. HDA - projekt wstępny 1.2 Postawienie problemu i jego analiza Zadaniem naszym jest skonstruowanie automat do wydawania hotdogów nazywanego w skrócie HDA (hot-dog automat). Przyjmijmy, że automat może wydać następujące rodzaje produktów: bułkę, bułkę z parówką, bułkę z parówką i musztardą. Koszt związany z nabyciem odpowiedniego produktu, to odpowiednio 2, 3 i 5 zł. Zakładamy, że automat akceptuje monety o nominałach 1, 2 i 5 zł i nie wydaje reszty. Ponadto zakładamy, że akceptowana jest tylko najmniejsza liczba monet z dopuszczalnego zbioru (a więc np. nie można wrzucić 2 razy po 2 zł i 1 raz 1 zł). Na rysunku 1.1 przedstawiono schemat projektowanego automatu. 1.3 Identyfikacja sygnałów wejściowych i wyjściowych Jeśli chcemy zaprojektować układ elektroniczny sterujący HDA, to musimy określić co będzie stanowiło sygnał wejściowy i jakie sygnały powinien automat generować. Potem zastanowimy się nad ich wzajamną relacją, tj. jakie sygnały wejściowe powodują powstanie jakich sygnałów wyjściowych. Sygnały wejściowe – sygnały powstające w otoczeniu układu; układ nie ma bezpośredniego wpływu na ich pojawienie się. Sygnały wyjściowe – sygnały wytwarzane przez układ i kierowane do jego otoczenia. Zbiór sygnałów wejściowych zestawiono w tabeli 1.2 natomiast wyjściowych w tabeli 1.3. Po ich uwzględnieniu projekt przyjmie postać jak na rysunku 1.2. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.4 Troszkę bardziej formalny opis działania układu sterującego Przyczyna pojawienia się sygnału wejściowego Wrzucenie monety o niminale 1 Wrzucenie monety o niminale 2 Wrzucenie monety o niminale 5 Naciśnięcie przycisku START 9 Wejście x1 x2 x5 xS Tablica 1.2. Sygnały wejściowe Działanie podjęte przez automat Wydanie bułki Wydanie parówki Wydanie musztardy Zwrot monet Wyjście yB yP yM yZ Tablica 1.3. Sygnały wyjściowe 1.4 Troszkę bardziej formalny opis działania układu sterującego Tak więc zadaniem projektowanego układu sterującego jest wytworzenie sygnałów wyjściowych yB , yP , yM oraz yZ na podstawie sygnałów wejściowych x1 , x2 , x5 , xS . Ujmując to bardziej precyzyjnie dążymy do skonstruowania takiej funkcji f (·), która pozwoli na odwzorowanie zależności pomiędzy sygnałami wejściowymi i wyjściowymi. Tak więc należy wyznaczyć 4 funkcje: yB = fB (x1 , x2 , x5 , xS ), yP = fP (x1 , x2 , x5 , xS ), yM = fM (x1 , x2 , x5 , xS ), yS = fS (x1 , x2 , x5 , xS ). Przyjmując za x wektor [x1 , x2 , x5 , xS ] natomiast za y wektor y1 , y2 , y5 , yS możemy to samo zapisać w następujący sposób y = f (x), f : A → A, Rys. 1.2. HDA - kolejny projekt c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 (1.1) 10 Zbuduj sobie HDA Wejście tylko wrzucono monety S 1+S 2+S 5+S 1+2+S 1+5+S 2+5+S 1+2+5+S Działanie podjęte przez automat Wyjście NOP — NOP ZWROT otwórz pojemnik z bułką otwórz pojemnik z bułką, parówka i musztardą otwórz pojemnik z bułką i parówka ZWROT ZWROT ZWROT — yZ yB yB + yP + yM yB + yP yZ yZ yZ Tablica 1.4. Sygnały wejściowe, działanie, sygnały wyjściowe gdzie A = {0, 1} × {0, 1} × {0, 1} × {0, 1}. Związek pomiędzy sygnałami z otoczenia automatu, działaniem jakie wykona urządzenie oraz sygnałami wyjściowymi zestawiono w tabeli 1.4. Wszystkie możliwe kombinacje sygnałów wejściowych i odpowiadające im reakcje automatu w postaci wygenerowania odopowiednich sygnałów wyjściowych zestawiono w tabeli 1.5. Spróbujemy teraz to co przedstawiono w tabeli 1.5 zapisać przy pomocy wyrażeń Boolowskich. Rozważania zacznijmy od kolumny yM jako, że tylko w jednym przypadku yM przyjmuje wartość równą 1: yM = 1 [x1 , x2 , x5 , xS ] = [0, 0, 1, 1]. jeżeli Zapisując to troszkę bardziej „matematycznie” otrzymujemy: yM = 1 jeżeli x1 = 0 ∧ x2 = 0 ∧ x5 = 1 ∧ xS = 1, a więc: yM = 1 jeżeli x̄1 ∧ x̄2 ∧ x5 ∧ xS , co pisząc skrótowo daje ostatecznie yM = 1 jeżeli x̄1 x̄2 x5 xS . Postąpmy teraz podobnie z sygnałem yP . yP = 1 jeżeli [x1 , x2 , x5 , xS ] = [0, 0, 1, 1] lub [x1 , x2 , x5 , xS ] = [1, 1, 0, 1]. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.4 Troszkę bardziej formalny opis działania układu sterującego 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 x1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 x2 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 x5 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 xS 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 yB 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 yP 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 yM 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 yZ 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 1 Tablica 1.5. Sygnały wyjściowe, działanie, sygnały wyjściowe Zapisując to troszkę bardziej „matematycznie” otrzymujemy: yP = 1 jeżeli ∨ x1 = 0 ∧ x2 = 0 ∧ x5 = 1 ∧ xS = 1 x1 = 1 ∧ x2 = 1 ∧ x5 = 0 ∧ xS = 1, a więc: yP = 1 jeżeli x̄1 ∧ x̄2 ∧ x5 ∧ xS ∨ x1 ∧ x2 ∧ x̄5 ∧ xS , co pisząc skrótowo daje ostatecznie yP = 1 jeżeli x̄1 x̄2 x5 xS + x1 x2 x̄5 xS . Sygnał yB . yB = 1 jeżeli [x1 , x2 , x5 , xS ] = [0, 0, 1, 1] lub [x1 , x2 , x5 , xS ] = [0, 1, 0, 1] lub [x1 , x2 , x5 , xS ] = [1, 1, 0, 1]. Zapisując to troszkę bardziej „matematycznie” otrzymujemy: yB = 1 jeżeli x1 = 0 ∧ x2 = 0 ∧ x5 = 1 ∧ xS = 1 ∨ x1 = 0 ∧ x2 = 1 ∧ x5 = 0 ∧ xS = 1 ∨ x1 = 1 ∧ x2 = 1 ∧ x5 = 0 ∧ xS = 1, c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 11 12 Zbuduj sobie HDA a więc: yB = 1 jeżeli x̄1 ∧ x̄2 ∧ x5 ∧ xS ∨ x̄1 ∧ x2 ∧ x̄5 ∧ xS ∨ x1 ∧ x2 ∧ x̄5 ∧ xS , co pisząc skrótowo daje ostatecznie yB = 1 jeżeli x̄1 x̄2 x5 xS + x̄1 x2 x̄5 xS + x1 x2 x̄5 xS . Sygnał yZ . yZ = 1 jeżeli lub lub lub [x1 , x2 , x5 , xS ] = [0, 1, 1, 1] [x1 , x2 , x5 , xS ] = [1, 0, 0, 1] [x1 , x2 , x5 , xS ] = [1, 0, 1, 1] [x1 , x2 , x5 , xS ] = [1, 1, 1, 1]. Zapisując to troszkę bardziej „matematycznie” otrzymujemy: yZ = 1 jeżeli ∨ ∨ ∨ x1 x1 x1 x1 = 0 ∧ x2 = 1 ∧ x2 = 1 ∧ x2 = 1 ∧ x2 = 1 ∧ x5 = 0 ∧ x5 = 0 ∧ x5 = 1 ∧ x5 = 1 ∧ xS = 0 ∧ xS = 1 ∧ xS = 1 ∧ xS =1 =1 =1 = 1, a więc: yZ = 1 jeżeli ∨ ∨ ∨ x̄1 ∧ x2 ∧ x5 ∧ xS x1 ∧ x̄2 ∧ x̄5 ∧ xS x1 ∧ x̄2 ∧ x5 ∧ xS x1 ∧ x2 ∧ x5 ∧ xS , co pisząc skrótowo daje ostatecznie yZ = 1 jeżeli x̄1 x2 x5 xS + x1 x̄2 x̄5 xS + x1 x̄2 x5 xS + x1 x2 x5 xS . 1.5 Podstawowe bramki Tutaj narysować bramki AND, OR, NOT; podać tablicę prawdy dla nich; powiedzieć jakim operacjom boolowskim odpowiadają te bramki. Narysować bramki NAND i NOR. Wprowadzić pojęcie systemu funkcjonalnie pełnego. NAND • NOT y = N AN D(x, x) = N OT (AN D(x, x)) = N OT (x); c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.5 Podstawowe bramki 13 Rys. 1.3. Bramki AND, OR i NOT Rys. 1.4. Bramki NAND i NOR • OR y = N AN D(x̄1 , x̄2 ) = N OT (AN D(x̄1 , x̄2 )) = N OT (x̄1 x̄2 ) ¯1 + x̄ ¯ 2 = x1 + x2 ; = x̄ • AND z = N AN D(x1 , x2 ) = N OT (AN D(x1 , x2 )) y = N AN D(z) = N OT (AN D(z, z)) = N OT (z) = N OT (N OT (AN D(x1 , x2 ))) = AN D(x1 , x2 ) NOR • NOT y = N OR(x, x) = N OT (OR(x, x)) = N OT (x); • AND y = N OR(x̄1 , x̄2 ) = N OT (OR(x̄1 , x̄2 )) = N OT (x̄1 + x̄2 ) ¯1 x̄ ¯ 2 = x1 x2 ; = x̄ • OR z = N OR(x1 , x2 ) = N OT (OR(x1 , x2 )) y = N OR(z) = N OT (OR(z, z)) = N OT (z) = N OT (N OT (OR(x1 , x2 ))) = OR(x1 , x2 ) Definicja 1.1 (System funkcjonalnie pełny). Systemem funkcjonalnie pełnym nazywamy zbiór operatorów, który jest w stanie wyrazić dowolne wyrażenie logiczne. Z definicji wynika, że trójka operatorów AND, OR oraz NOT stanowi układ funkcjonalnie pełny. Układ funkcjonalnie pełny stanowi także np. OR i NOT. Co ciekawe istnieją także operatory, które w połączeniu same z sobą pozwalają uzyskać równoważnik funkcji AND, OR i NOT a więc tworzą c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 14 Zbuduj sobie HDA x1 0 0 1 1 x2 0 1 0 1 NAND(x1 ,x2 ) 1 1 1 0 NOR(x1 ,x2 ) 1 0 0 0 Tablica 1.6. Definicja funkcji NAND i NOR układ funkcjonalnie pełny. Operatorami tymi jest operator NAND i NOR. Dla ścisłości wywodu zauważmy, że istnieją tylko dwa operatory dwuargumentowe o takiej własnści (patrz informacje dla dociekliwych 1.1 na stronie 14). Definicje tych operatorów zawiera tabela 1.6. Dla dociekliwych 1.1. Dwuargumentowym funktorem zdaniotwórczym (dalej będziemy pisać: funktorem) nazwiemy funkcję przyporządkowującą każdemu układowi < x1 , x2 >, gdzie x1 , x2 ∈ {0, 1}, 0 oznacza fałsz, 1 – prawdę, wartość 0 lub 1. Wszystkie funktory, jedno lub dwuargumentowe dają się zdefiniować za pomocą alternatywy i negacji. Istnieją funktory dwuargumentowe, które wystarczają do zdefiniowania wszystkich funktorów jedno i dwuargumentowych. Jak udowodnił E.Żyliński są tylko dwa takie funktory: • o15 1 pochodzący od H.M.Scheffera nazywany dyzjunkcją (zdanie a o15 b czytamy: nie a lub nie b); wówczas negacja to: a o15 a a alternatywa to (a o15 a) o15 (b o15 b); • o5 pochodzący od J.Łukasiewicza nazywany jednoczesnym zaprzeczeniem; wówczas negacja to: a o5 a a alternatywa to (a o5 b) o5 (a o5 b). 1.6 1.6.1 Tworzenie schematu układu Etap I Rysujemy odpowiednie schematy cząstkowe odpowiadające funkcjom generującym sygnały wyjściowe (rys. 1.5). 1 Oznaczenie odnosi się do oznaczeń użytych w tabeli 1.7. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.7 Minimalizacja układu poprzez minimalizację wyrażenia logicznego15 0 0 1 1 0 1 0 1 0 0 1 1 0 1 0 1 o1 0 0 0 0 o9 0 1 1 0 o2 0 0 0 1 o10 1 0 1 0 o3 0 0 1 0 o11 1 1 0 0 o4 0 1 0 0 o12 0 1 1 1 o5 1 0 0 0 o13 1 0 1 1 o6 0 0 1 1 o14 1 1 0 1 o7 0 1 0 1 o15 1 1 1 0 o8 1 0 0 1 o16 1 1 1 1 Tablica 1.7. Funktory dwuargumentowe Rys. 1.5. Pierwsza wersja schematu HDA 1.6.2 Etap II Redukujemy powtarzające się elementy układu (rys. 1.6). 1.7 Minimalizacja układu poprzez minimalizację wyrażenia logicznego Niestety podobne zabiegi do tych właśnie przeprowadzonych nie dadzą się zastosować do układu generującego sygnał yZ . W tym przypadku musimy zminimalizować wyrażenia algebraiczne opisujace ten sygnał. yZ = x̄1 x2 x5 xS + x1 x̄2 x̄5 xS + x1 x̄2 x5 xS + x1 x2 x5 xS = x2 x5 xS (x1 + x̄1 ) + x1 x̄2 xS (x5 + x̄5 ) = xS (x2 x5 + x1 x̄2 ). Jako wynik przeprowadzonej minimalizacji otrzymujemy układ przedstawiony na rysunku (rys. 1.7). 1.8 Mnemotechniczne sposoby minimalizacji wyrażeń logicznych Przeprowadzone do tej pory operacje minimalizacji układów miały jedną zasadniczą wadę – wymagały myślenia. Mówiąc inaczej, wymagały inter- Rys. 1.6. Uproszczony schemat HDA c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 16 Zbuduj sobie HDA Rys. 1.7. Uproszczony schemat HDA wencji człowieka i jego aktywnego udziału w procesie. W tym przypadku było to proste, ale chyb nikt nie ma wątpliwości, że w przypadku bardziej złożonych układów, ludzie nie są w stanie zanalizować ich poprawinie i dokonać optymalnych zmian. Stąd też zajmiemy się teraz poszukiwaniem pewnych sposobów zautomatyzowania procesu upraszczania wyrażeń boolowskich a tym samym upraszczania złożonych układów. Definicja 1.2 (Jedynka funkcji). Jedynką funkcji nazywamy wektor zerojedynkowy, dla którego funkcja przyjmuje wartość 1. Definicja 1.3 (Reguła sklejania). Jeżeli dwa iloczyny różnią się między sobą tylko na jednym miejscu, w którym w jednym z iloczynów dany literał2 występuje w afirmacji3 a w drugim w negacji, to literał ten może być usunięty, w wyniku czego powstaje pojedyńczy iloczyn nie zawierający tego literału. Regułę można zapisać w postaci: bB + b̄B = (b + b̄)B = B, gdzie B jest iloczynem pozostałych literałów z wyjątkiem b (oraz b̄). Tak więc minimalizację wyrażenia logicznego można osiągnąć przez analizowanie wektorów zerojedynkowych reprezentujących poszczególne jedynki funkcji (patrz przykład 1.1). Przykład 1.1. analiza wektorów zero-jedynkowych algebraiczna analiza wyrażenia y=~x1*x2*x5*xS + x1*x2*x5*xS = (~x1+x1)*x2*x5*xS= | | = 1*x2*x5*xS= | | = x2*x5*xS 0111 1111 | | | | a więc +-----+-------+ | | a więc | | | 2 Literał czyli symbol nazwy sygnału. Piszemy „literał”, gdyż mamy na myśli cały symbol, który czasem może być wieloliterowy. 3 Ze słownika języka polskiego: afirmajcja – potwierdzenie czegoś, uznanie, aprobata. W tym kontekście oznacza to sygnał niezanegowany. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.8 Mnemotechniczne sposoby minimalizacji wyrażeń logicznych różnica na -> _111 jednym miejscu 17 _111 Wypisując wszystkie jedynki funkcji i sumując je otrzymujemy wyrażenie będące sumą iloczynów. Każdy z czynników jest w tym przypadku iloczynem pełnym, czyli takim, który zawiera wszystkie literały. Taką postać wyrażenia nazywamy Kanoniczną Alternatywna Postacią Normalną (Kanoniczną Postacią Normalną Sumy). Po minimalizacji czynniki nie będą już pełnymi iloczynami – taką postać nazywać będziemy wówczas Alternatywną Postacią Normalną (Postacią Normalną Sumy). Dualną postacią do PNS jest Koniunkcyjna Postać Normalna i jest to jak łatwo zgadnąć iloczyn sum odpowiednich wyrażeń. Opierając się na regule sklejania w łatwy sposób możemy redukować wyrażenia. Kłopot polega jednak na zautomatyzowaniu tego procesu. Spróbujmy wykonać kilka doświadczeń związanych z minimalizowaniem wyrażeń. 1. Zminimalizujmy wartość wyrażenia w = ābc̄d + abc̄d. Mamy w = ābc̄d + abc̄d = bc̄d(ā + a) = bc̄d. Utwórzmy teraz pewną tabelę, nie wnikając w to dlaczego tak a nie inaczej ona wygląda. \cd| \ | ab\|00 01 11 10 ---+----------00 | 01 | 11 | 10 | Wypełniamy teraz tabelę symbolami 1 i 0 stosownie do badanego wyrażenia. I tak ponieważ w minimalizowanym wyrażeniu mamy abc̄d więc stawiamy 1 na przecięciu wiersz oznaczonego jako 11 (odpowiednik ab) oraz kolumny 01 (odpowiednik c̄d). Podobnie postępujemy z drugim czynnikiem. W pozostałe pola wpisujemy wartość 0, otrzymując ostatecznie c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 18 Zbuduj sobie HDA \cd| \ | ab\|00 01 11 10 ---+----------00 | 0 0 0 0 01 | 0 1 0 0 11 | 0 1 0 0 10 | 0 0 0 0 Zauważmy, że „ jedynki” są „obok siebie” tworząc prostokąt a w wyrażeniu jakie jest wynikiem minimalizacji pozostały te element indeksu kolumny i wiersza, które są wspólne dla obu „ jedynek”. Przejdźmy do kolejnego przykładu. 2. Zminimalizujmy wartość wyrażenia w = ābc̄d + ābcd + abcd. Mamy w = ābc̄d + ābcd + abcd = ābc̄d + ābcd + ābcd + abcd = (c̄ + c)ābd + (ā + a)bcd = ābd + bcd. Ponownie jak poprzednio wypełniamy tabelę symbolami 1 i 0 stosownie do badanego wyrażenia, otrzymując: \cd| \ | ab\|00 01 11 10 ---+----------00 | 0 0 0 0 01 | 0 1 1 0 11 | 0 0 1 0 10 | 0 0 0 0 W tym przypadku „ jedynki” również są obok siebie, ale ich układ jest troszkę inny. Jeśli jednak dopuścimy możliwość wielokrotnego wykorzystania pewnej „ jedynki” wówczas możemy mówić o dwóch nachodzących na siebie parach „ jedynek” tworzących dwa prostokąty: \cd| \ | ab\|00 01 11 10 ---+----------- \cd| \ | ab\|00 01 11 10 ---+----------- c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.8 Mnemotechniczne sposoby minimalizacji wyrażeń logicznych 00 01 11 10 | | | | 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 00 01 11 10 | | | | 0 0 0 0 0 1 0 0 0 1 0 0 19 0 0 0 0 Wielokrotne wykorzystanie „ jedynki” jest oczywiście uzasadnione teoretycznie jako, że w dowolnym wyrażeniu boolowskim możemy dowolny z czynników dopisać tyle razy ile chcemy, w myśl jednego z praw: x = x + x. Ponieważ mieliśmy tutaj dwie grupy po dwie „ jedynki” więc zminimalizowane wyrażenie ma dwa czynniki. Ponownie w każdym z wyrażeń usunięto zmienną, która miała różną wartość dla każdej z jedynek (w parze). 3. Zminimalizujmy wartość wyrażenia w = ābc̄d + ābcd + abc̄d + abcd. Mamy w = ābc̄d + ābcd + abc̄d + abcd = ābd + abd = abd. Wypełniamy tabelę symbolami 1 i 0 stosownie do badanego wyrażenia, otrzymując: \cd| \ | ab\|00 01 11 10 ---+----------00 | 0 0 0 0 01 | 0 1 1 0 11 | 0 1 1 0 10 | 0 0 0 0 Ponownie „ jedynki” są obok siebie a o układzie jaki tworzą można powiedzieć, iż jest to szczególny przypadek prostokąta – kwadrat. Zauważmy, że ponownie w minimalizowanym wyrażeniu pozostały jedynie te indeksy wierszy i kolumn z „ jedynkami” które nie ulegały zmianie. ¯ 4. Zminimalizujmy wartość wyrażenia w = abc̄d¯ + abc̄d + abcd + abcd. Mamy w = abc̄d¯ + abc̄d + abcd + abcd¯ = abc̄ + abc = ab. Wypełniamy tabelę symbolami 1 i 0 stosownie do badanego wyrażenia, otrzymując: c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 20 Zbuduj sobie HDA \cd| \ | ab\|00 01 11 10 ---+----------00 | 0 0 0 0 01 | 0 0 0 0 11 | 1 1 1 1 10 | 0 0 0 0 Ponownie „ jedynki” są obok siebie i tworzą prostokąt. ¯ 5. Zminimalizujmy wartość wyrażenia w = āb̄c̄d¯ + āb̄cd¯ + ab̄c̄d¯ + ab̄cd. Mamy ¯ w = āb̄c̄d¯ + āb̄cd¯ + ab̄c̄d¯ + ab̄cd¯ = āb̄d¯ + ab̄d¯ = b̄d. Wypełniamy tabelę symbolami 1 i 0 stosownie do badanego wyrażenia, otrzymując: \cd| \ | ab\|00 01 11 10 ---+----------00 | 1 0 0 1 01 | 0 0 0 0 11 | 0 0 0 0 10 | 1 0 0 1 Jeśli teraz dopuścimy możliwość „zawijania” tabeli (czyli przyjmiemy, że ostatnia kolumna jest sąsiednia w stosunku do pierwszej; podobnie z wierszami), wówczas ponownie „ jedynki” są obok siebie i tworzą prostokąt. Jaki wniosek można wyciągnąc z przedstawionych przykładów? Otórz jeśli mając dane pewne wyrażenie uda nam się uzupełnić tabelkę w ten sposób aby umieszczone w niej „ jedynki” pogrupować w prostokąty (nazywane ogólnie klatkami), wówczas z danego prostokąta wybieramy tylko te symbole, które dla wszystkich „ jedynek” pozostały niezmienne; symbole te utworzą minimalizowane wyrażenie. Ważne jest aby pamiętać, że prostokąty muszą zawierać 2k elementów, przy czym k = 1, . . . , n, gdzie n jest ilością argumentów funkcji4 . 4 Nie można tego akurat zauważyć na prezentowanych przykładach, ale pozostawiamy c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.9 Kod Gray’a 21 1-bitowy 0 1 2-bitowy 0 0 0 1 1 1 1 0 3-bitowy 0 0 0 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 4-bitowy 0 0 0 0 0 1 0 1 1 0 1 0 1 1 0 1 1 1 1 0 1 1 0 0 1 0 0 1 0 1 1 1 1 1 1 0 0 1 0 0 1 1 0 0 1 0 0 0 Tablica 1.8. 1-, 2-, 3- i 4-bitowe kody Greya 1.9 Kod Gray’a Kluczem do sukcesu przy minimalizacji wyrażeń w przykładach z poprzedniego podrozdziału był sposób wypełniania tabeli a właściwie sposób numerowania jej wierszy i kolumn. Zauważmy, że każde dwa wiersze czy kolumny (uwzględniając możliwość „zawijania”) różnią się tylko jednym symbolem. I tak np. wiersz „trzeci” numerowany jako 11 różni się od „czwartego” numerowanego jako 10 na drugiej pozycji numeru; pierwsza jest taka sama i jest nią „ jedynka”. Tak więc bardzo pożądaną umiejetnością jest zdolnośc do konstruowania kodów mających właśnie taką własność – dwa sąsiednie kody różnią się tylko na jednej pozycji. Własność taką posiada na przykład Kod Greya. Tablica 1.8 zawiera przykłady 1-, 2-, 3- i 4-bitowych kodów Greya. wykonanie kilku prób jako ćwiczenie dla czytelnika. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 22 Zbuduj sobie HDA Rys. 1.8. Tablice Karnaugha dla funkcji 3, 4, 5 i 6 argumentów 1.10 Tablice Karnaugha Pomysł wykorzystania kodów Greya do konstruowania tablic podobnych to tych z przykładu pochodzi od M. Karnaugh (1953 r.).Stąd też tablice tego typu nazywamy tablicami Karnaugha. Przykładowe tablice Karnaugha dla funkcji 3, 4, 5 i 6 zmiennych przedstawiono na rysunku 1.8. Uzupełnijmy teraz wiadomości o tablicach Karnaugha o informacje, których w podanych przykładach nie było. Zacznijmy od wartości nieokreślonych. Otórz czasem zdarza się tak, że pewna kombinacja sygnałów wejściowych nie może wystąpić – na przykład żarówka jest albo włączona, albo wyłączona; nie może być częściowo włączona5 . Wówczas podczas uzupełniania tablicy pozostaną nam pola nieokreślone. Każde takie nieokreślone pole może mieć wartość 1 lub 0 w zależności od naszych potrzeb. Mówiąc inaczej, to my ustalamy jaką wartość ma pole nieokreślone. Nie ma to dla układu żadnego znaczenia bo przecież i tak nigdy taka sytuacja nie wystąpi. Popatrzmy na kolejne przykłady. 1. Zminimalizujmy wartość wyrażenia w = āb̄c̄d¯ + ābc̄d¯ + ab̄c̄d¯ wiedząc, ¯ Wypełniamy tabelę symbolami że nie wystąpi układ sygnałów: abc̄d. 1 i 0 stosownie do badanego wyrażenia, otrzymując: \cd| \ | ab\|00 01 11 10 ---+----------00 | 1 0 0 0 01 | 1 0 0 0 11 | ? 0 0 0 10 | 1 0 0 0 W tym przypadku wygodnie jest przyjąć, że w pole odpowiadające ¯ wyrażeniu abc̄d¯ wpisujemy wartość 1. Tak więc w = c̄d. 2. Zminimalizujmy wartość wyrażenia w = ābc̄d + ābcd wiedząc, że nie 5 Dopuszczając nawet istnienie sprytnych układów umożliwiajacych przyciemnianie światła powiemy co najwyżej, że żarówka słabiej świeci, ale nie powiemy, że świeci i nie świeci w tym samym czasie. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.10 Tablice Karnaugha 23 ¯ Wypełniamy tabelę symbolami 1 i 0 wystąpi układ sygnałów: āb̄cd. stosownie do badanego wyrażenia, otrzymując: \cd| \ | ab\|00 01 11 10 ---+----------00 | 0 0 0 ? 01 | 0 1 1 0 11 | 0 0 0 0 10 | 0 0 0 0 W tym przypadku wygodnie jest przyjąć, że w pole odpowiadające wyrażeniu āb̄cd¯ wpisujemy wartość 0. Tak więc w = ābd. Zauważmy, że dotychczas zawsze otrzymywaliśmy wyrażenie w Alternatywnej Postaci Normalnej, czyli sumy iloczynów. Aby uzyskać równoważną Koniunkcyjną Postań Normalną, czyli iloczyn sum nieznacznie musimy zmodyfikować nasze działania: • do tabeli wpisujemy zera funkcji (zamiast jedynek jak to miało miejsce do tej pory); • wspólne literały z klatki stanowią sumę; • pomiędzy sumami otrzymanymi z klatek piszemy znak iloczynu; • literały wchodzące w skład sumy są wstawiane w afirmacji jeśli literał ma w klatce wartość 0 i w negacji, jeśli dany literał ma wartość 1. Projektując funkcje realizujące odpowiednie odwzorowanie możemy żądać aby uzyskane wyrażenie algebraiczne było w jednej z dwóch wspomnianych form. W szczególności rozważmy takie zadanie. Utworzyć wyrażenie algebraiczne w postaci sumy iloczynów i iloczynu sum realizujące związek pomiędzy wejściem i wyjściem opisany tabelką 1.9. W tabelce tej dodano także dwie dodatkowe kolumny: suma iloczynów oraz iloczyn sum – wartości z tych kolumn posłużą nam do budowy odpowiednich wyrażeń. Jeśli chcemy otrzymać wyrażenie w postaci sumy iloczynów, wówczas w kolumny opisanej jako suma iloczynów bierzemy te wiersze, dla których wyjście równe jest 1 i łączymy je operatorem sumy. Chcąc otrzymać wyrażenie w postaci iloczynu sum wybieramy te wiersze z kolumny opisanej jako iloczyn sum, dla których wyjście równe jest 0 i łączymy je operatorem iloczynu. Tak więc w naszym przypadku otrzymujemy c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 24 Zbuduj sobie HDA Wejście x y 0 0 0 1 1 0 1 1 Wyjście z 1 0 1 1 Sumy iloczynów x̄ȳ x̄y xȳ xy Iloczyny sum x+y x + ȳ x̄ + y x̄ + ȳ Tablica 1.9. tutu x1 0 0 0 0 1 1 1 1 Wejście x2 x3 0 0 0 1 1 0 1 1 0 0 0 1 1 0 1 1 Wyjście y 0 0 1 1 0 0 1 0 Sumy iloczynów x̄1 x̄2 x̄3 x̄1 x̄2 x3 x̄1 x2 x̄3 x̄1 x2 x3 x1 x̄2 x̄3 x1 x̄2 x3 x1 x2 x̄3 x1 x2 x3 Iloczyny sum x1 + x2 + x3 x1 + x2 + x̄3 x1 + x̄2 + x3 x1 + x̄2 + x̄3 x̄1 + x2 + x3 x̄1 + x2 + x̄3 x̄1 + x̄2 + x3 x̄1 + x̄2 + x̄3 Tablica 1.10. tutu suma iloczynów z = x̄ȳ + xȳ + xy = ȳ(x̄ + x) + x(ȳ + y) = ȳ + x; iloczyn sum z = x + ȳ W przykładzie tym dosyć łatwo można zaobserwować jak tworzy się odpowiednie wyrażenia wpisywane do dwóch ostatnich kolumn. Niestety z dydaktycznego punktu widzenia posiada on pewną niedoskonałość. O ile widać jasno, że za pierwszym razem otrzymaliśmy wyrażenie w postaci sumy iloczynów, o tyle wrażenie w postaci iloczynu sum. . . jest iloczynem sum, ale bez iloczynu. Rozważmy zatem jeszcze jeden przykład, w którym stanie się to wyraźniejsze. Relacje pomiędzy wejściem a wyjściem opisuje tabelka 1.10. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 1.10 Tablice Karnaugha 25 suma iloczynów y = x̄1 x2 x̄3 + x̄1 x2 x3 + x1 x2 x̄3 = x̄1 x2 (x̄3 + x3 ) + x2 x̄3 (x̄1 + x1 ) = x̄1 x2 + x2 x̄3 ; iloczyn sum y = (x1 + x2 + x3 )(x1 + x2 + x̄3 )(x̄1 + x2 + x3 ) · (x̄1 + x2 + x̄3 )(x̄1 + x̄2 + x̄3 ) = [(x1 + x2 ) + (x3 x̄3 )][(x̄1 + x2 ) + (x3 x̄3 )] · [(x̄1 + x̄3 ) + (x2 x̄2 )] = (x1 + x2 )(x̄1 + x2 )(x̄1 + x̄3 ) = [x2 + (x1 x̄1 )](x̄1 + x̄3 ) = x2 (x̄1 + x̄3 ). Oczywiście w obu tych przykładach możemy skorzystać z tablic Karnaugh. Zacznijmy od wyrażenia w postaci sumy iloczynów. y = x̄1 x2 x̄3 + x̄1 x2 x3 + x1 x2 x̄3 = . . . Tworząc odpowiednią tablicę, otrzymujemy \x_3 \ | x_1 x_2\| 0 | 1 | --------+---+---+ 0 0 | 0 1 | 1 1 1 1 | 1 1 0 | a więc = x̄1 x2 + x2 x̄3 . Zajmijmy się teraz drugą z postaci kanonicznych, tj. postacią iloczynu sum. y = (x1 + x2 + x3 )(x1 + x2 + x̄3 )(x̄1 + x2 + x3 ) · (x̄1 + x2 + x̄3 )(x̄1 + x̄2 + x̄3 ) = ... Tworząc odpowiednią tablicę, otrzymujemy c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 26 Zbuduj sobie HDA \x_3 \ | x_1 x_2\| 0 | 1 | --------+---+---+ 0 0 | 0 0 0 1 | 1 1 | 0 1 0 | 0 0 co daje (mamy dwie klatki: pierwsza i druga kolumna z pierwszego i ostatniego wiersza oraz druga kolumna z ostatniego i przedostaniego wiersza) · · · = x2 (x̄1 + x̄3 ). c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Rozdział 2 Dwie bramki to już układ W rozdziale 1 zapoznaliśmy się z podstawowymi pojęciami, elementami i sposobami opisu układów cyfrowych. Teraz spróbujemy tę wiedzę wykorzystać projektując różne mniej lub bardziej złożone układy. Jak później zobaczymy, z tych układów tworzy się układy o większej złożoności a z tychże tworzy się. . . procesor. A podstawą zawsze są „zwykłe” bramki. 2.1 Komparator jednobitowy Układ tego typu porównuje ze sobą dwa bity – jeśli są takie sam, to zwraca wartość 1, jeśli zaś różne to 0. Związek pomiędzy sygnałami wejściowymi i wyjściowymi przedstawiono w tabeli 2.1. Bazujac na wcześniej zdobytej wiedzy, otrzymujemy, następujące wyrażenie opisujące sygnał na wyjściu układu y = ī1 ī2 + i1 i2 . Odpowiedni schemat przedstawiono na rysunku 2.1. Komparator jednobitowy jest cegiełką, która posłuży nam do zbudowania komparatora nWejście i1 i2 0 0 0 1 1 0 1 1 Wyjście o 1 0 0 1 Tablica 2.1. Zależnośc pomiędzy wejściem i wyjściem komparatora 1-bitowego c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 28 Dwie bramki to już układ Rys. 2.1. Komparator 1-bitowy. Rys. 2.2. Komparator 4-bitowy bitowego, w naszym przypadku 4-bitowego; odpowiedni schemat przedstawiono na rysunku 2.2. 2.2 Sumator jednobitowy Kolejnym, wydaje się niezbędnym, elementem każdego procesora jest sumator. Podobnie jak z komparatorem, rozważa się sumator 1-bitowy a następnie z niego buduje się sumatory n-bitowe. Jak sama nazwa mówi, układ tego typu odpowiedzialny jest za wykonywanie jednej z 4 podstawowych operacji arytmetycznych – dodawania. Sumator posiada następujące wejścia i wyjścia wejścia • ci (ang. carry in) – sygnał przeniesienia z poprzedniej pozycji; dzieki niemu możemy łączyć sumatory 1-bitowe celem dodawania liczb o większej liczbie bitów; • i1 , i2 – dodawane bity; • co (ang. carry out) – przeniesienie do następnej pozycji; wyjścia • o – bit sumy danych i1 oraz i2 . Związek pomiędzy sygnałami wejściowymi i wyjściowymi przedstawiono w tabeli 2.2. Otrzymujemy, następujące wyrażenia opisujące sygnały na wyjściu układu co = c̄i i1 i2 + ci ī1 i2 + ci i1 ī2 + ci i1 i2 , o = c̄i ī1 i2 + c̄i i1 ī2 + ci ī1 ī2 + ci i1 i2 . Narysujmy teraz tablice Karnaugha dla obu tych wyrażeń. \c_i \c_i c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 2.2 Sumator jednobitowy 29 Wejście ci i1 i2 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 Wyjście co o 0 0 0 1 0 1 1 0 0 1 1 0 1 0 1 1 Tablica 2.2. Zależnośc pomiędzy wejściem i wyjściem sumatora 1-bitowego \ | i_1 i_2\| 0 | 1 | --------+---+---+ 0 0 | 0 1 | 1 1 1 | 1 1 1 0 | 1 \ | i_1 i_2\| 0 | 1 | --------+---+---+ 0 0 | 1 0 1 | 1 1 1 | 1 1 0 | 1 Jak widać wyrażenie co możemy uprościć w oparciu o tablicę, natomiast w stounku do drugiego musimy niestety wykazać się inteligencją. Zacznijmy od podstawowych przekształceń: o = c̄i ī1 i2 + c̄i i1 ī2 + ci ī1 ī2 + ci i1 i2 = c̄i (ī1 i2 + i1 ī2 ) + ci (ī1 ī2 + i1 i2 ) = ... (2.1) Zauważmy teraz, że zachodzi następujący związek: i¯1 i2 + i1 i¯2 = (i¯1 i2 )(i1 i¯2 ) = (i1 + ī2 )(ī1 + i2 ) = (i1 + ī2 )i1 + (i1 + i¯2 )i2 = i¯1 i¯2 + i1 i2 . Tak więc przyjmując podstawienie s = ī1 i2 + i1 ī2 otrzymujemy o = · · · = c̄i s + ci s̄. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 (2.2) 30 Dwie bramki to już układ Rys. 2.3. Układ generujący sygnał co Rys. 2.4. Układ generujący sygnał o Schematy układów generujących sygnały wyjściowe co i o przedstawiono na rysunkach 2.3 oraz 2.4. Na rysunku 2.5 przedstawiono symboliczny zapis układu będącego sumatorem 1-bitowym natomiast rysunek 2.6 przedstawia schemat sumatora 4-bitowego. 2.3 Dekoder adresowy Dekoder to inaczej układ przekształcający jeden kod binarny na inny. Budowa dekodera uzależniona jest od realizowanego zadania. W tym przypadku będziemy mieć do czynienia z dekoderem adresowym, czyli układem wybierającym jedną z kilku możliwości (konkretnie: jedną z kilku komórek pamięci) na podstawie podanego adresu. Ustalmy zatem, że wybieramy jedną spośród 4 komórek pamięci. Zatem układ powinien mieć 4 wyjścia. Sygnał o wartości 1 powinien być zawsze tylko na jednym wyjściu – tym Rys. 2.5. Symboliczny zapis układu będącego sumatorem 1-bitowym c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 2.3 Dekoder adresowy 31 Rys. 2.6. Schemat sumatora 4-bitowego Wejście a1 a2 0 0 0 1 1 0 1 1 o1 1 0 0 0 Wyjście o2 o3 o4 0 0 0 1 0 0 0 1 0 0 0 1 Tablica 2.3. Zależność pomiędzy wejściem i wyjściem 4-bitowego dekodera adresowego wskazanym przez adres. Do wskazania jednej z 4 możliwych liczb potrzebujemy 2 bitów, zatem układ będzie miał 2 wejścia. Zależności pomiędzy wejściami i wyjściami zebrano w tabeli 2.3 natomiast schemat układu przedstawiono na ryskunku 2.7 Mamy więc już opracowany dekoder adresowy, a więc układ „wskazujący” jedną, wybraną, komórkę pamięci. Teraz powinniśmy dodać układ realizujący odczyt wybranej w ten sposób komórki. Wejściem dla takiego D układu są wejścia z dekodera iD 1 -i4 oraz wejścia z poszczególnych komóM M rek układu pamięci i1 -i4 . Na wyjściu o, które jest tylko jedno, powinien pojawić się sygnał z wybranej komórki pamięci. Schemat takiego układu Rys. 2.7. Dekoder adresowy c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 32 Dwie bramki to już układ Rys. 2.8. Układ realizujący odczyt komórki pamięci wskazanej przez 4-bitowy dekoder adresowy Wejście R S 0 0 0 1 1 0 1 1 Wyjście Q Q bez zmian 0 1 1 0 niedozwolone Tablica 2.4. Zależność pomiędzy wejściem i wyjściem przerzutnika R-S przedstawiono na rysunku 2.8. 2.4 Przerzutniki Przerzutniki posiadają zwykle kilka wejść sterujących i dwa wyjścia o przeciwnych stanach, oznaczane zwykle Q oraz Q. 2.4.1 Przerzutniki typu R-S Przerzutniki tego typu posiadają dwa wejścia: • R – (ang. reset), • S – (ang. Set) i dwa wyjścia: Q oraz Q. Gdy na wejściach R i S podany zostanie sygnał o wartości 0, wówczas przerzutnik nie zmienia swojego stanu. Podanie na wejście S stanu 1 (przy jednoczesnym podaniu na wejście R stanu 0) powoduje ustawienie wyjścia Q na 1. Podanie stanu 0 na wejście S (przy jednoczesnym podaniu na wejście R stanu 1) powoduje ustawienie na wyjściu Q stanu 0. Zauważmy, że pojawienie się na obu wejściach sygnału o wartości 1 powoduje, że zarówno wyjście Q jak i Q są w stanie 0 co nie jest dozwolone. Tabelka 2.4 opisuje zależności pomiędzy stanem sygnałów R i S oraz Q i Q. Schemat przerzutnika R-S oraz jego symbol przedstawiono na rysunku 2.9. Jak widać przerzutnik Rys. 2.9. Schemat przerzutnika R-S a) oraz jego symbol b) c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 2.4 Przerzutniki 33 Wejście R S 0 0 0 1 1 0 1 1 Wyjście Q Q niedozwolone 1 0 0 1 bez zmian Tablica 2.5. Zależność pomiędzy wejściem i wyjściem przerzutnika R-S Rys. 2.10. Schemat przerzutnika R-S a) oraz jego symbol b) tpu R-S zbudowany jest w oparciu o bramki NOR. Stosując bramki NAND również otrzymujemy przerzutnik, oznaczany czasem dla odmiany R-S. W tym przypadku zależność pomiędzy wejściem i wyjściem opisuje tabela 2.5. Jak widać zachowanie przerzutnika jest podobne, ale pod wpływem innych sygnałów. Teraz niedozwolone jest podanie na oba wejścia jednocześnie sygnału 0. Sygnał o wartości 1 na obu wejściach oznacza brak zmiany stanu przerzutnika. Wyjście Q staje się aktywne, po podaniu sygnału o wartości 0 na wejście S. Wyjście Q przyjmie stan 0 jeśli na wejściu R pojawi się sygnał o wartości 1. Zauważmy, że przerzutnik zbudowany w oparciu o bramki NAND, przechodzi w stan aktywny (sygnał o wartości 1 na wyjściu Q) gdy podamy na wejście S sygnał o wartości 0. W takich przypadkach na wejściu układu będziemy rysować kółeczka podobne do tych przy bramce NOR czy też NAND. Schemat przerzutnika zbudowanego w oparciu o bramki NAND oraz jego symbol przedstawia rysunek 2.10. 2.4.2 Hazard Wszystkie rozważane do tej pory układy były idealne. Ich idealność polegała na natychmiastowej reakcji każdej bramki; inaczej mówiąc czas reakcji bramki na zmianę sygnałów wejściowych wynosi 0. I nie ma znaczenia z ilu bramek układ jest zbudowany – podając sygnał na wejście w tym samym momencie otrzymujemy sygnał na wyjściu. Niestety w rzeczywistości nie jest tak pięknie. Właściwy poziom sygnału na wyjściu każdej bramki ustala się dopiero po upływie pewnego czasu, tzw. czasu propagacji. W konsekwencji stan całego układ ustala się dopiero po pewnym czasie. Zanim to nastąpi, stan wyjść nie jest określony żadną funkcją logiczną gdyż nawet dwa identyczne układy mogą się zachowywać odmiennie z uwagi na c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 34 Dwie bramki to już układ Rys. 2.11. 3 bramki NOT połączone szeregowo Rys. 2.12. Czasy propagacji sygnałów w układzie z rysunku 2.11 pewne różnice w parametrach tworzących je układów1 . Przyjrzyjmy się poniższemu przykładowi. Przykład 2.1. Propagacja sygnału. Rozważmy uład składający się z szeregowo połączonych bramek NOT (rysunek 2.11). Z teoretycznego punktu widzenia, trzy bramki NOT powinny dać w efekcie na wyjściu negację sygnału wejściowego o = N OT (N OT (N OT (i))) = N OT (i) Załóżmy, że na wejście układu podajemy sygnał o wartości 1. Zanim nie minie odpowiedni czas t nic nie możemy powiedzieć o stanie sygnału na wyjściu bramki g2 oraz g3 . Mówic inaczej, sygnał musi tam dopiero „dopłynąć”. Tak więc oczekiwaną wartość 0 na wyjściu układu otrzymamy dopiero po czsie 3t (patrz rysunek 2.12). Dobrze by zatem było aby istniał jakiś mechanizm zapewniający dostęp do „dobrych” sygnałów, a więc tych już ustabilizowanych. Jednym ze sposobów jest wprowadzenie sygnłu synchronizującego układy. Najczęściej jest to sygnał, w którym stan 0 i 1 pojawiają się naprzemiennie i trwają tyle samo czsu – stąd mówimy o nim sygnał zegarowy, lub też mówimy o taktowaniu. Okres taktu zegarowego2 powinien być oczywiście dobrany w taki sposób aby zdążyły ustalić się w tym czasie stany wszystkich bramek. Stan układu analizowany jest dopiero przy końcu taktu zegarowego. Teraz może łatwiej będzie zrozumieć dlaczego zwiększanie „szybkości procesora” to taki trudny temat3 . Zwiększanie częstotliwości pracy pociąga za sobą konieczność skonstruowania układów o mniejszym czasie propagacji. Bez tego, samo zwiększani częstotliwości taktowania doprowadzi nas do sytuacji gdy sieć nie będzie zdolna do ustabilizowania się w ramach jednego 1 Dodajmy, że mówimy tutaj o różnicach mieszczących się z zakresie tolerancji danego parametru a więc np. z punktu widzenia producenta układy są identyczne. 2 Czyli czas trwania stanu 0 lub 1. Ilość zmian stanu w ciągu sekundy wyrażamy w hercach (Hz). 3 Poza tym mamy nadzieję, że w końcu wyjaśniło się po co są te „gigaherce” w komputerze. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 2.4 Przerzutniki 35 Wejście R S C 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 Wyjście Q Q bez zmian bez zmian bez zmian 1 0 bez zmian 0 1 bez zmian niedozwolone Tablica 2.6. Zależność pomiędzy wejściem i wyjściem synchronicznego przerzutnika R-S Rys. 2.13. Przerzutnik synchroniczny typu R-S i jego symbol taktu zegara. Przy okazji zauważmy, że bramka logiczna pobiera najwięcej energii w momencie zmiany swojego stanu. Zwiększenie taktowania powoduje zwiększenie liczby zmiany stnów w danej jednostce czsu, czyli większe zużycie energii, czyli więcej ciepła wydzielanego przez układ. To wyjaśnia trochę dlaczego niektóre współczesne procesory służyć mogą jako przepływowe ogrzewacze wody. 2.4.3 Synchroniczny przerzutnik typu R-S Najłatwiejszy sposób na uzyskanie synchronizowanego przerzutnika jest dodanie, do „zwykłego” przerzutnika typu R-S, dwóch bramek typu NAND, których zadaniem jest blokowanie sygnałów z wejść R i S tak długo jak sygnał zegarowy C jest nieaktywny (ma wartość 0). Zależność pomiędzy wejściem a wyjściem zebrano w tabeli 2.6 natomiast odpowiedni schemat i symbol przerzutnika przedstawia rysunek 2.13. Zauważmy, że „zezwolenie” nia działanie układu może zostać przekazana przez sygnał taktujacy na 4 sposoby: • przez wysoki stan sygnału taktującego (odpowiedni symbol przerzutnika na rysunku 2.14 a)), • przez niski stan sygnału taktującego (rysunek 2.14 b)), • przez narastające zbocze sygnału taktującego (rysunek 2.14 c)), c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 36 Dwie bramki to już układ Rys. 2.14. Symbole odpowiadające przerzutnikom z 4 sposobami wyzwalania: a) – stanem wysokim, b) – stanem niskim, c) – narastającym zboczem, d) – opadającym zboczem Rys. 2.15. Przerzutnik typu D • przez opadające zbocze sygnału taktującego (rysunek 2.14 d)). Przerzutniki wyzwalane stanem sygnału zegarowego nazywamy przerzutnikami statycznimi lub też zatrzaskami (ang. latch); przerzutniki wyzwalane zboczem sygnału segarowego nazywamy przerzutnikami dynamicznymi. 2.4.4 Przerzutnik typu D Przerzutnik typu D to kolejna wariacja na temat przerzutnika typu R-S a dokładnie jego synchronicznej mutacji. Otóż do synchronicznego przerzutnika R-S dodajemy bramkę NOT w taki sposób, że wejście R jest zanegowany sygnałem z wejścia S (patrz rysunek 2.15). Działanie przerzutnika polega na przenoszeniu stanu z wejścia D na wyjście Q w czasie trwania stanu aktywnego na wejściu C. Gdy wejście wyzwalające przejdzie w stan nieaktywny, przerzutnik zapamiętuje ostatnio ustawiony stan. Dokładne zależności pomiędzy wejściem i wyjściem zawiera tabela 2.7. Jak niebawem się przekonamy takie działanie wykorzystywane jest np. przy tworzeniu liczników. 2.4.5 Przerzutnik typu J-K Przerzutnik typu J-K otrzymujemy z synchronicznego przerzutnika typu R-S wyzwalanego opadającym zboczem sygnału zegarowego przez dodanie Wejście D C 0 0 0 1 1 0 1 1 Wyjście Q Q — — 0 1 — — 1 0 Tablica 2.7. Zależność pomiędzy wejściem i wyjściem przerzutnika typu D c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 2.5 Rejestr 37 Wejście J K 0 0 0 1 1 0 1 1 Wyjście Q Q — — 0 1 1 0 ! — ! — Tablica 2.8. Zależność pomiędzy wejściem i wyjściem przerzutnika typu J-K Rys. 2.16. Przerzutnik typu J-K dwóch bramek AND (rysunek 2.16). Zależność pomiędzy wejściami i wyjściami przedstawia tabelka 2.8. 2.5 Rejestr Mając odpowiednią bazę w postaci różnych typów przerzutnikow powracamy teraz do układów złożonych. Zadaniem rejestrów jest przede wszystkim przechowywanie danych. Zasadnicze różnice pomiędzy rejestrami skupiają się na sposobie zapisu (równoległy, szeregowy) oraz odczytu danych a także ilości bitów jakiej jednocześnie operacje te dotyczą. Na rysunku 2.17 przedstawiono schemat rejestru 4-bitowego. Wejściami danych są i1 , i2 , i3 oraz i4 . Służą one jak łatwo zgadnąć do wprowadzania danych. Aby dane zostały zapisane, na wejściu w musi nastąpić zmiana sygnału z 0 na 1 (zapis przy narastającym zboczu). Informację zapisaną w rejestrze możemy odczytać z wyjść o1 , o2 , o3 , o4 . 2.6 Pamięć Do zbudowania układu pamięci potrzebny będzie nam dekoder adresowy wraz z układem realizującym odczyt wybranej przez dekoder komórki pamięci (patrz punkt 2.3) oraz komórki pamięci (patrz 2.5). Jako, że wszystkie wymagane składniki zostaly już omówione, wystarczy je tylko połączyć w funkcjonalną całość. Schemat układu pamięci przedstawia rysunek 2.18. Rys. 2.17. Rejestr zbudowany z przerzutników typu D c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 38 Dwie bramki to już układ Rys. 2.18. Schemat układu będącego 4-bitową pamięcią Rys. 2.19. Podstawowy układ zliczający zbudowany w oparciu o przerzutnik typu D 2.7 Licznik Licznik jest układem zliczającym w impulsy podawane na jego wejście. W swej najprostszej postaci, licznik dokonuje zliczania w naturalnym kodzie bitowym. Podstawowym elementem konstrukcyjnym jest układ, zmieniający swój stan na przeciwny przy każdorazowym podaniu sygnału na jedno z wejść. Pozostając w kręgu poznanych układów, element taki można skonstruować w oparciu o przerzutnik typu D co pokazano na rysunku 2.19. Łacząc ze sobą kilka takich układów możemy w prosty sposób uzyskać licznik zliczające większą ilość wystąpień sygnału. Przykład dla licznika 4-bitowego przedstawia rysunke 2.20. Wykres czasowy stanów poszczególnych wyjść przedstawiono na rysunku 2.21. Dodajmy jeszcze, że tak skonstruowane liczniki nazywać bedziemy asynchronicznymi gdyż poszczególne przerzutniki nie przełączają się jednocześnie, lecz z pewnym opóźnieniem, wynikającym z czasu propagacji sygnału w poprzednim przerzutniku. Rys. 2.20. Licznik 4-bitowy c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 2.7 Licznik Rys. 2.21. Zmiany stanów poszczególnych wyjść licznika 4-bitowego w czasie c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 39 40 Dwie bramki to już układ c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Rozdział 3 Dlaczego 2+2=5? I am a HAL Nine Thousand computer [. . . ] The quick brown fox jumps over the lazy dog [. . . ] Dave – are you still there? Did you know that the square root of 10 is 3.162277660168379? Log 10 to the base e is 0.434294481903252. . . correction, that is log e to the base 10 [. . . ] 2 times 2 is. . . 2 times 2 is. . . approximately 4.10101010. . . I seem to be having difficulty HAL, 2001: A Space Odyssey 3.1 Dlaczego? Ograniczenia jakie niesie ze sobą format IEEE 754 zapisu liczby zmiennoprzecinkowej są widoczne i oczywiste po uważniejszym jemu przyjrzeniu się. Zasadniczym motywem zbadania jego był to, że kiedyś dodając na komputerze dwie liczby, obie miały część ułamkową dwucyfrową, otrzymałem liczbę całkowitą. I nie byłoby w tym nic dziwnego gdyby nie to, że części ułamkowe nie sumowały się do liczby całkowitej. Poirytowany tym faktem postanowiłem więc przyjrzeć się uważniej wspomnianemu formatowi. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 42 3.2 Dlaczego 2+2=5? Doświadczenie 1 Tak więc na tapetę wzięty został format IEEE 754 a dokładniej mówiac jego modyfikacja wykorzystująca 8 bitów. Format taki przedstawiony został w [3]. Przypominijmy, że przyjmujemy następujące znaczenie bitów: pierwszy bit od lewej oznacza znak liczby, kolejne 3 mantysę zaś ostatnie 4 bity będą cechą. Jako wartość stałej KC (odejmowanej od cechy) przyjmijmy 7. Tak więc liczby dające się zapisać w tym formacie są postaci zm M · 2C−KC , gdzie zm to znak mantysy, M – mantysa, C – cecha. Tak przyjęty format jest dużo protszy do analizy (ze względu na mniejszą ilość bitów) a przy tym raczej nie fałszuje w sposób istotnych względnych wyników (tj. stosunku poprawnych i błędnych obliczeń). Dla ułatwienia wzięte zostały pod obserwację tylko liczby dodatnie. Najpierw stworzony został program generujący wszystkie liczby jakie można zapisać w tym formacie. #define K_C 7 [...] //przyjmuje nastepujaca kolejnosc bitow //b2 b1 b0 c3 c2 c1 c0 char b2,b1,b0,c3,c2,c1,c0; int cecha,i=0,j,k,blad=0,zakres=0; float mantysa; double t[128]; //przebieg po cesze for(c3=0;c3<=1;c3++) for(c2=0;c2<=1;c2++) for(c1=0;c1<=1;c1++) for(c0=0;c0<=1;c0++) { cecha=c0*1+c1*2+c2*4+c3*8-K_C; //przebieg po mantysie for(b2=0;b2<=1;b2++) for(b1=0;b1<=1;b1++) c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 3.2 Doświadczenie 1 43 for(b0=0;b0<=1;b0++) { mantysa=1.0+0.5*b2+0.25*b1+0.125*b0; t[i]=wypisz(b2,b1,b0,c3,c2,c1,c0,mantysa,cecha); i++; } } Funkcja Wypisz zdefiniowana została jak poniżej double Wypisz(char b2,char b1,char b0,char c3,char c2,char c1, char c0,float mantysa,int cecha) { double r; fprintf(stdout,"%c",b2==0?’0’:’1’); fprintf(stdout,"%c",b1==0?’0’:’1’); fprintf(stdout,"%c",b0==0?’0’:’1’); fprintf(stdout,"%c",c3==0?’0’:’1’); fprintf(stdout,"%c",c2==0?’0’:’1’); fprintf(stdout,"%c",c1==0?’0’:’1’); fprintf(stdout,"%c",c0==0?’0’:’1’); r=mantysa*pow(2,cecha); fprintf(stdout," : %f*2^%d=%.10f",mantysa,cecha,r); fprintf(stdout,"\n"); return r; } I tak, zgodnie z oczekiwaniami najmniejszą możliwą do reprezentowania liczbą jest 0.0078125 zapisane jako 0000000 (1.000000 · 2−7 ), zaś największa to 480.0 zapisane jako 1111111 (1.875000 · 28 ); łącznie mamy oczywiście 128 różnych liczb. Teraz przyszedł czas na najważniejszą część tego doświadczenia. Biorąc oto wszystkie możliwe kombinacje dwóch spośród otrzymanych 128 liczb, sprawdzamy czy ich suma jest jedną z tych 128 liczb. Mówiąc inaczej sprawdzamy czy suma dwóch spośród owych 128 liczb daje się wyrazić w tym formacie. //szukam zlych sum for(i=0;i<128;i++) for(j=0;j<128;j++) { c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 44 Dlaczego 2+2=5? for(k=0;k<128;k++) { if(t[i]+t[j]==t[k]) { k=255; break; } } if(k!=255) { if(t[i]+t[j]<=t[127]) { blad++; fprintf(stdout,"%.10f+%.10f=%.10f",t[i],t[j], t[i]+t[j]); fprintf(stdout," ERROR\n"); } else { zakres++; fprintf(stdout,"%.10f+%.10f=%.10f",t[i],t[j], t[i]+t[j]); fprintf(stdout," ZAKRES\n"); } } } fprintf(stdout,"Lacznie bledow %d, poza zakresem %d (%d)\n", blad,zakres,128*128); Zauważmy, że łacznie mamy 128·128 = 16384 możliwości. Wyniki nie są optymistyczne. Otóż 434 sumy są poza zakresem obejmowanym przez tak przyjęty format (np. 480+480 daje 960). Trudno o to mieć jednak pretensje – ograniczona ilość bitów skutkuje ograniczonym zakresem. Pozostaje więc 15950 sum. Z tego 14232 nie dają się wyrazić w tym formacie. Oznacza to, że jedynie 1718 sum jest prawidłowych. Reszta to będą przybliżenia. Zatem jedynie 9.28% wyników jest poprawna!!! Gdyby opuścić wszystkie sumy, które się powtarzają, czyli nie rozróżniać czy dodajemy x1 do x2 czy na odwrót: x2 do x1 , wówczas mamy 8256 różnych sum, z których 221 jest poza zakresem naszego formatu a 7121 nie daje się wyrazić w tym formacie. Oznacza to, że jedynie 914 sum jest c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 3.3 Doświadczenie 2 45 prawidłowych, czyli 11.37%. Już samo to co napisano powyżej wystarcza do tego aby przenieść się z prowadzeniem obliczeń na liczydła. Zróbmy jednak jeszcze jeden test. Bierzmy więc dwie kolejne liczby i liczmy ich różnicę. Otrzymamy w ten sposób wartość mówiącą nam o dokładności reprezentacji. Wyniki zebrano w tabeli 3.1. Dla czytelności pominięte zostały różnice dające takie same wyniki. I tak patrząc na wiersz o liczbie porządkowej 127 mamy tam różnicę (dwóch kolejnych) liczb 480 i 448 wynoszącą 32. Oznacza to, że żadna liczba całkowita (nie mówiąc już o rzeczywistych) większa od 448 a mniejsza od 480 nie daje się wyrazić w przyjętym formacie. Każda z takich liczb będzie zaokrąglona „w górę” do 480 lub „w dół” do 448 w zależności od przyjętych algorytmów. 3.3 Doświadczenie 2 Z pewnością wszystkim doskonale znany jest przypadek Lorenza i jego motyla opisany w „Can the flap of a butterfly wing stir up a tornado in Texas”. Problem dotyczy powstawania i akumulacji błędów zaokrągleń i związany jest z niemożnością przewidywania w deterministycznych układach ze sprzężeniem zwrotnym w tym także w matematycznych modelach, które wykorzystywano do długoterminowych analiz pogody. Jak to zwykle bywa na problem ten Lorentz natrafił przez przypadek. Zaczęło się to wszystko gdzieś około roku 1956, kiedy pewne metody przewidywania [pogody] zostały zaproponowane [. . . ] jako najlepsze z dostępnych, z czym się jednak nie zgadzałem. Zadecydowałem sam wysmażyć niewielki układ równań symulujących zachowanie atmosfery, rozwiązać go za pomocą komputerów, które wtedy właśnie zaczęły być dostępne, a następnie potraktować wyniki tak, jakby to były rzeczywiste dane z obserwacji atmosferycznych, i sprawdzić, czy proponowane metody stosują się do nich. Prawdziwym problemem było uzyskanie takiego układu równań, który doprowadziłby do wyników nadających się do przetestowania, ponieważ szybko stało się jasne, że jeśli rozwiązanie tych równań będzie cykliczne, to proponowane metody będą trywialne, a tym samym będą stosowały się idealnie. Musieliśmy więc otrzymać układ równań, mający rozwiązania niecykliczne, takie które nie powtarzają się, ale przebiegają nieregularnie i w sposób niezdefiniowany. Znalazłem w końcu układ dwunastu równań, które to spełniały i sprawdziłem, że proponowane metody nie były odpowiednie. Gdy to robiłem chciałem sprawdzić niektóre z wyników w sposób bardziej szczegółowy. W swoim biurze miałem wtedy mały komputer, wpisałem więc kilka pośrednich c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 46 Dlaczego 2+2=5? L.p. 1 8 9 16 17 24 25 32 33 40 41 48 49 56 57 64 65 72 73 80 81 88 89 96 97 104 105 112 113 120 121 127 x 0.0078125000 0.0146484375 0.0156250000 0.0292968750 0.0312500000 0.0585937500 0.0625000000 0.1171875000 0.1250000000 0.2343750000 0.2500000000 0.4687500000 0.5000000000 0.9375000000 1.0000000000 1.8750000000 2.0000000000 3.7500000000 4.0000000000 7.5000000000 8.0000000000 15.0000000000 16.0000000000 30.0000000000 32.0000000000 60.0000000000 64.0000000000 120.0000000000 128.0000000000 240.0000000000 256.0000000000 448.0000000000 y 0.0087890625 0.0156250000 0.0175781250 0.0312500000 0.0351562500 0.0625000000 0.0703125000 0.1250000000 0.1406250000 0.2500000000 0.2812500000 0.5000000000 0.5625000000 1.0000000000 1.1250000000 2.0000000000 2.2500000000 4.0000000000 4.5000000000 8.0000000000 9.0000000000 16.0000000000 18.0000000000 32.0000000000 36.0000000000 64.0000000000 72.0000000000 128.0000000000 144.0000000000 256.0000000000 288.0000000000 480.0000000000 y−x 0.0009765625 0.0009765625 0.0019531250 0.0019531250 0.0039062500 0.0039062500 0.0078125000 0.0078125000 0.0156250000 0.0156250000 0.0312500000 0.0312500000 0.0625000000 0.0625000000 0.1250000000 0.1250000000 0.2500000000 0.2500000000 0.5000000000 0.5000000000 1.0000000000 1.0000000000 2.0000000000 2.0000000000 4.0000000000 4.0000000000 8.0000000000 8.0000000000 16.0000000000 16.0000000000 32.0000000000 32.0000000000 Tablica 3.1. Różnice pomiędzy kolejnymi wartościami c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 3.3 Doświadczenie 2 47 wartości, które komputer wydrukował, jako nowe warunki początkowe dla następnych obliczeń, i na chwile wyszedłem. Kiedy wróciłem, zobaczyłem, że rozwiązania były inne niż przedtem; komputer zachowywał się inaczej. W pierwszej chwili podejrzewałem, że mam jakieś kłopoty z komputerem, jednak wkrótce odkryłem, że prawdziwą przyczyną jest to, iż liczby wpisane przeze mnie różniły się od liczb wyjściowych, które zaokrągliłem, i ta niewielka różnica pomiędzy czymś rozwiniętym do szóstego miejsca po przecinku i jego zaokrągleniem do trzeciego miejsca w czasie symulacji dwóch miesięcy pogody stała się tak wielka jak sam sygnał. Wynikało z tego, że jeżeli prawdziwa atmosfera zachowuje się w podobny sposób, to nie jesteśmy po prostu w stanie przewidzieć pogody na dwa miesiące naprzód. Te małe błędy będą się powiększać, aż staną się wielkie 1 . Postanowiłem więc sprawdzić jak to faktczynie z tym motylem jest. Jako temat dalszych rozważań wybrałem tak zwany model logistyczny a więc rekurencyjne wyrażenie następującej postaci pn+1 = pn + rpn (1 − pn ) (3.1) oraz jego „drugą” postać otrzymaną przez zastosowanie elementarnych przekształceń algebraicznych (tak więc z matematycznego punktu widzenia oba te wyrażenia, jeśli nawet nie są takie same, to dają takie same wyniki) pn+1 = (1 + r)pn − rp2n . (3.2) W powyższych równaniach r jest pewną stałą, natomiast n i n+1 to indeksy odpowiednio poprzedniego i nowo obliczanego wyrazu. Jako wartość stałej r przyjęto 3.0 natomiast jako wyraz a1 przyjęto wartość 0.01. Dla obu wzorów dokonano po 500-set iteracji na dwóch różnych typach liczbowych: float i double. Kilka przykładowych wyników przedstawiono w tabeli 3.2. Zamieszczone w niej dane należy czytać w następujący sposób. W ramach każdej iteracji mamy trzy wiersze: pierwszy to wynik obliczeń przeprowadzonych na zmiennych typu float, drugi na zmiennych typu double trzeci zaś to różnica pomiędzy tymi wynikami. Tak więc porównanie wiersza pierwszego i drugiego daje nam pojęcie o wpływie przyjętej reprezentacji na prowadzone obliczenia (w ramach tego samego wzoru). Jeśli natomiast chcemy porównać ze sobą wzory, to interesuje nas pierwsza kolumna od prawej, w której to zawarto różnice pomiędzy wartościami otrzymanym za pomocą obu wzorów. I tak na przykład w iteracji 399 mamy, że dla wzoru 3.1 różnica pomiędzy wartościami obliczonymi przy użyciu zmiennych typu 1 W: [4], s. 79. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 48 Dlaczego 2+2=5? Iteracja Według wzoru 3.1 Według wzoru 3.2 1 0.009999999776483 0.010000000000000 -0.000000000223517 0.070538848638535 1.189384903904431 -1.118846055265897 0.267228215932846 0.513630266710465 -0.246402050777619 0.099408328533173 0.967600411062598 -0.868192082529425 0.856545627117157 1.298726103232332 -0.442180476115175 0.260175228118896 0.940545426832992 -0.680370198714096 0.009999999776483 0.010000000000000 -0.000000000223517 0.070538848638535 1.189384903904431 -1.118846055265896 0.267228215932846 0.513630266710467 -0.246402050777621 0.099408328533173 0.961800737412491 -0.862392408879318 0.856545627117157 0.008244384236384 0.848301242880773 0.260175228118896 0.257679774120511 0.002495453998385 257 258 300 399 500 Różnice pomiędzy wzorami 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 -0.000000000000000 0.000000000000000 -0.000000000000001 0.000000000000001 0.000000000000000 0.005799673650107 -0.005799673650107 0.000000000000000 1.290481718995948 -1.290481718995948 0.000000000000000 0.682865652712481 -0.682865652712481 Tablica 3.2. Różnice pomiędzy kolejnymi wyrazami otrzymanymi za pomocą wzorów 3.1 oraz 3.2 c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 3.4 Wnioski 49 float i double wynosi −0.442180476115175. Ta sama różnica dla wzoru 3.2 wynosi 0.848301242880773. Zauważmy, że różnice są tego samego rzędu co obliczane wartości! Jeśli natomiast chodzi o różnice pomiędzy wzorami to dla typu double wynosi ona 1.290481718995948. Zastanawiający może być fakt braku różnic dla typu float. tutu W tym momencie nie mam wiarygodnego wyjaśnienia, choć mam kilka hipotez :) Oba wzory dają takie same wyniki do 257 iteracji2 . Na zakończenie jeszcze jeden test – test wrażliwościowy. Sprawdzimy jaki wpływ na wyniki obliczeń ma zakłócenie warunków początkowych. To całkiem tak jak przy pogodzie – zrobiliśmy pomiar temperatury powietrza i „trochę” się pomyliliśmy. Tabela 3.3 prezentuje część wyników. Pierwszy wiersz dla każdej iteracji policzony został dla współczynnika r = 3.0, drugi dla r = 3.000000000001, trzeci dla r = 3.0000000000001, czwarty dla r = 3.00000000000001. Zmniejszenie części ułamkowej o następny rząd wielkości, dawało dobre wyniki przez 20000 iteracji. Powodem tego może być niemożność odwzorowania liczby 3 z tak małą częścią ułamkową i zaokrąglenie jej do 3.0 lub też błędy na dalszych, niewyświetlanych, pozycjach co jest raczej wątpliwe bo po tylu iteracjach powinny one stać się widoczne. 3.4 Wnioski Przedstawione w 3.2 rozważania, mimo iż bardzo uproszczone, ukazują jednak cechy zmiennopozycyjnego sposobu reprezentacji liczb rzeczywistych w komputerze. Należy mieć świadomość, że zwiększenie ilości bitów służących do reprezentacji liczby nie wnosi nowej jakości. Owszem, możliwe, że w takm przypadku zamiast 1718, poprawnych będzie 1 milion sum. Ciągle będzie to jednak ok 10% wszystkich możliwych kombinacji. Dla większości i tak będziemy zmuszeni użyć przybliżenia. Zwiększenie ilości bitów skutkuje jedynie przesunięciem pewnych granic, ale nie ich zlikwidowaniem (np. w rozważanym formacie można przedstawić wszystkie liczby całkowite z zakresu [1,15]; powyżej bywa już różnie). W szczególności na przykładzie dwóch ostatnich liczb widać, jak duże niedokładności pociąga za sobą używanie „dużych” (dużych dla danego formatu) liczb3 . W punkcie 3.3 chcieliśmy natomiast zwrócić uwagę na stabilność obliczeń numerycznych. Oto okazuje się, że nie ma nic bardziej niepewnego niż 2 3 Mówiąc dokładniej: wyniki są takie same biorąc pod uwagę 15 miejsc po przecinku. Podobnie sprawa wygląda w przypadku „małych” liczb. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 50 Dlaczego 2+2=5? Iteracja 1 2 3 4 5 6 7 51 Współczynnik 3.0 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 3.0 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 3.0 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 3.0 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 3.0 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 3.0 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 3.0 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 3.0+10E 3.0+10E-12 3.0+10E-13 3.0+10E-14 3.0+10E-15 Wyniki 0.039700000000000 0.039700000000010 0.039700000000001 0.039700000000000 0.039700000000000 0.154071730000000 0.154071730000075 0.154071730000008 0.154071730000001 0.154071730000000 0.545072626044421 0.545072626044783 0.545072626044457 0.545072626044425 0.545072626044422 1.288978001188801 1.288978001189313 1.288978001188852 1.288978001188806 1.288978001188801 0.171519142109176 0.171519142106890 0.171519142108948 0.171519142109153 0.171519142109174 0.597820120107100 0.597820120100453 0.597820120106437 0.597820120107033 0.597820120107094 1.319113792413797 1.319113792411292 1.319113792413548 1.319113792413772 1.319113792413795 0.074892694909774 0.462398200088556 0.056394912819080 1.280547749402646 0.178875826166109 Tablica 3.3. Wpływ niedokładności na otrzymywane wyniki c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 3.4 Wnioski 51 obliczenia przeprowadzone na komputerze. Ponownie „winę” za taki stan rzeczy ponosi przyjęty format zapisu liczb. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 52 Dlaczego 2+2=5? c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Rozdział 4 Obliczenia numeryczne 4.1 O strukturze pamięci Podczas pisania programów nie wystarczy myśleć; trzeba też wiedzieć. Trzeba wiedzieć, dużo pisać. A pisząc bacznie obserwować, bo nie każdy program choć taki sam działa tak samo. Przyjrzyjmy się oto dwum prawie identycznym fragmentom kodu. Oba robią to samo a „optyczna” różnica jest natury ideologicznej — bo to czy ktoś woli przechodzić po elementach tablicy wierszami czy kolumnami, to nic innego jak ideologia. Czy aby jednak tylko ideologia? for(w=0;w<100;w++) { for(k=0;k<1000;k++) { tab[w][k]+=tab[w][k]; } } for(k=0;k<1000;k++) { for(w=0;w<100;w++) { tab[w][k]+=tab[w][k]; } } Gdy umieścimy te linie w kodzie jakiegoś programu i uruchomimy go to ponownie nic nie zauważymy. Współczesne komputery osobiste są za szybkie aby coś zauważyć. Skoro nic nie widać, to powtórzmy ten fragment kodu kilkanaście razy w pętli. Kilkanaście, czyli na przykład 5000 razy. A powtarzając, zmierzmy czas potrzebny na wykonanie tych 5000 powtórzeń. timestart(); for(p=0;p<5000;p++) { timestart(); for(p=0;p<5000;p++) { c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 54 Obliczenia numeryczne Real 6,610 6,130 6,150 6,130 6,120 6,140 6,120 6,130 6,120 6,150 Program 1 User System 6,570 0,000 6,090 0,000 6,110 0,000 6,100 0,000 6,100 0,000 6,110 0,000 6,090 0,000 6,100 0,000 6,090 0,000 6,110 0,000 Real 8,200 8,150 8,140 8,180 8,180 8,160 8,160 8,170 8,160 8,160 Program User 8,140 8,130 8,130 8,150 8,150 8,140 8,140 8,150 8,140 8,140 2 System 0,000 0,000 0,010 0,000 0,000 0,000 0,000 0,000 0,000 0,000 Tablica 4.1. Czasy potrzebne na wykonanie programu 1 i programu 2. for(w=0;w<100;w++) { for(k=0;k<1000;k++) { tab[w][k]+=tab[w][k]; } } } timestop(); for(k=0;k<1000;k++) { for(w=0;w<100;w++) { tab[w][k]+=tab[w][k]; } } } timestop(); W tabeli 4.1 przedstawiam część wyników jakie udało mi się zebrać (wszystkie otrzymane wyniki wyglądały podobnie) Uśredniony czas „User” (to on informuje nas ile czasu procesora faktycznie zabrał nasz program) wynosi dla programu 1: 6,15 s, natomiast dla programu 2: 8,14 s. Jak więc widać, zależnie od tego, czy przebiegamy po tablicy wierszami czy kolumnami, możemy zanotować 30% spowolnienie programu. Czary czy magia? Nie, rzeczywistość. A rzeczywistość wygląda tak. . . Język C (bo w nim ten test był robiony) ma to do siebie, że każda tablica jednowymiarowa zajmuje ciągły obszar pamięci o rozmiarze odpowiednim do wymiaru tablicy i typu danych w niej przechowywanych. Tak więc tablica taka zajmuje ilość_elementów * rozmiar_elementu_w_bajtach komórek pamięci. Każda tablica dwuwymiarowa, traktowana natomiast jest jak tablica tablic. Tak więc tablica dwuwymiarowa tak naprawdę jest tablicą, której elementami są tablice. W naszym przypadku, skoro mamy float tab[100][1000];, więc mamy tablicę 100 elementową, gdzie każdy c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 4.2 O tym co, jak i w czym liczymy 55 element jest z kolei tablicą 1000 elementową a każdy element tejże tablicy jest liczbą rzeczywistą. Tak więc ta tablica dwuwymiarowa zajmie w pamięci 100*1000*rozmiar_float komórek pamięci. Co ważniejsze, pamięć zostanie zapisana wierszami. Tak więc najpierw w pamięci będą umieszczone elementy zerowego1 wiersza naszej tabeli, potem pierwszego, drugiego i tak aż do dziewięćdziesiątego dziewiątego. Dla tradycyjnego systemu komputerowego najlepszą sytuacją jest taka, gdy odczytuje kolejne elementy z obszaru pamięci w jakim zapisano tablicę. Takie „liniowe zachowanie” znacznie przyspiesza operacje związane z dostępem do pamięci, bo • pamieć odczytywana jest blokami, czyli jednocześnie pobierane jest kilka kolejnych komórek pamięci. Jeśli więc operujemy na kolejnych komórkach, to taki odczyt konieczny jest tylko raz na jakiś czas. • układom przewidującym, które obszary pamięci będą odczytywane w przyszłości, łatwiej wykonać to zadanie gdy nie skoaczemy po niej w losowy (z punktu widzenia ukłądu) sposób. Drugi z przedstawionych fragmentów kodu zmusza procesor do skakania po pamięci; oba te zachowania zostały przedstawione na rysunku ??. Tak więc myśleć trzeba, ale i trzeba też wiedzieć. A nie pisząc samemu nawet takich „głupawych” programów jak ten trudno sie czegoś dowiedzieć. 4.2 O tym co, jak i w czym liczymy Jednym z lepiej znanych przykładów zadania którego lepiej przy pomocy rekurencji nie rozwiązywać jest ciąg Fibonnaciego. Definiujemy go w następujący sposób: dla n > 1 mamy f ibn = f ibn−1 + f ibn−2 , natomiast wyrazy 1. i 0. przyjmują wartość 1. Drzewo wywołań rekurencyjnych rozrasta się w tym przypadku bardzo szybko, stanowiąc doskonałe uzasadnienie wyboru innych metod (np. iteracja). Przykład takiego drzewa dla obliczania szóstego wyrazu zamieszczamy poniżej FibR(5) | +--FibR(4) 1 Tablice w języku C indeksujemy poczynając od 0. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 56 Obliczenia numeryczne | | | +--FibR(3) | | | | | +--FibR(2) | | | | | | | +--FibR(1) | | | +--FibR(0) | | | | | +--Fib(1) | | | +--FibR(2) | | | +--FibR(1) | +--FibR(0) +--FibR(3) | +--FibR(2) | | | +--FibR(1) | +--FibR(0) | +--FibR(1) Pewnego dnia przygotowywując materiały na zajęcia postanowiłem pomierzyć zarówno czasy obliczeń jak i liczbę wywołań i otrzymane wartości dla n = 0, . . . , 40. Jako, że był to czas, gdy pisałem trochę w Pythonie, zaimplementowałem całość w tym właśnie języku. I pewno nic by się nie stało, gdyby nie fakt, że na Centrino Duo 1,66GHz otrzymałem wyniki o wiele gorsze niż przed paroma laty na 486 DX4 120 MHz. Postanowiłem więc lepiej przyjrzeć się innym językom i sposobom implementacji. Ogólnie test przeprowadziłem w następujących środowiskach (biorąc pod uwagę system operacyjny i komputer): • komputer 486 DX 4 120 MHz, środowisko MS-DOS, język C (kolumna: Czas 1); • komputer Intel Centrino Duo T2300 1.66GHz 981 MHz, 0.99GB RAM, środowisko Microsoft WindowsXP SP2,język C (kolumna: Czas 2 i 3); • komputer Intel Centrino Duo T2300 1.66GHz 981 MHz, 0.99GB RAM, środowisko Microsoft WindowsXP SP2,język Java (kolumna: Czas 4 c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 4.2 O tym co, jak i w czym liczymy 57 i 5); • komputer Intel Centrino Duo T2300 1.66GHz 981 MHz, 0.99GB RAM, środowisko Microsoft WindowsXP SP2,język Python (kolumna: Czas 6 i 7); • komputer Intel Centrino Duo T2300 1.66GHz 981 MHz, 0.99GB RAM, środowisko Ubuntu Linux 7.04, język Java (kolumna: Czas 8 i 9). • komputer Intel Centrino Duo T2300 1.66GHz 981 MHz, 0.99GB RAM, środowisko Ubuntu Linux 7.04, język Python (kolumna: Czas 10 i 11). Wszystkie parzyste czasy dotyczyły implementacji liczącej tylko wartość i mierzącej czas obliczeń. Nieparzyste implementacje (z wyjątkiem pierwszej) liczyły wartość wyrazu, liczbę wywołań oraz czas. Zanim przejdziemy do prezentacji wyników jeszcze krótkie przedstawienie dwóch wersji programu zaimplementowanego w Pythonie (wszystkie programy znajdują się w dodatku). #wersja obliczajaca wartość wyrazu, #ilość wywołań i czas from time import * def fib(n): if (n==0 or n==1): return {"wynik":1,"wywolanie":1}; res1=fib(n-1) res2=fib(n-2) v=res1["wynik"]+res2["wynik"] c=res1["wywolanie"]+res2["wywolanie"]+1 return {"wynik":v,"wywolanie":c} def FibCount(n): start=clock() v=fib(n) stop=clock() czas=stop-start print "Wyraz dla n=",n," wynosi ",v["wynik"]," (wywolan: ",v["wywolanie"],", czas: " for i in range(0,41,1): FibCount(i) c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 58 Obliczenia numeryczne #wersja obliczajaca wartość wyrazu i czas from time import * def fib(n): if (n==0 or n==1): return 1; return fib(n-1)+fib(n-2) def FibCount(n): start=clock() v=fib(n) stop=clock() czas=stop-start print "Wyraz dla n=",n," wynosi ",v," czas: ",(czas),"s" for i in range(0,41,1): FibCount(i) Wyniki: OS/L n 30 31 32 33 34 35 36 37 38 39 40 486 T1 2 2,56 3,54 5,10 7,11 12,67 18,84 29,40 48,12 75,82 >90,0 Win C T2 T3 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 2 3 4 3 6 6 9 Win J T4 T5 Win T6 1,2 2,0 3,2 5,3 8,6 13,9 22,5 36,5 59,0 95,6 154,7 Pyt T7 8,5 13,3 20,9 33,2 53,2 85,4 — — — — — Lin J T8 T9 0,018 0,225 0,028 0,359 0,046 0,577 0,076 0,929 0,121 1,502 0,19 2,43 0,304 3,90 0,49 6,327 0,791 10,209 1,273 16,572 2,066 26,822 Lin T10 1,47 2,38 3,85 6,22 10,07 16,36 26,58 42,85 69,25 112,15 182,85 c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Pyt T11 3,78 5,96 9,64 15,63 25,57 41,08 66,43 107,09 173,78 280,43 454,27 Rozdział 5 Architektury równoległe 5.1 Podział Obliczenia równoległe 5.2 Klasyfikacja architektur równoległych według Flynna Na nasze potrzeby, podobnie jak w [2], wprowadzimy pojęcie strumienia. Strumieniem nazywać będziemy pewną sekwencję (ciąg) obiektów lub akcji. Obiektem mogą być np. dane a akcją instrukcje. Każdy strumień jest niezależny od innych strumieni. Każdy element strumienia może składać się z jednego lub więcej obiektu lub akcji. Mając sprecyzowane co rozumiemy pod pojęciem strumienia, możemy teraz wyszczególnić cztery najbardziej popularne architektury równoległe: 1. SISD (ang. single instruction stream, single data stream). Najprostszy przypadek, kiedy to zasadniczo nie mamy do czynienia z równoległościa. Odpowiada temu każdy „tradycyjny” procesor. Klasa ta opisuje architektury typu von Neumanna, gdzie szeregowo (sekwencyjnie) pobierany jest pojedyńczy zestaw rozkazów operujących na pojedynczych danych. 2. SIMD (ang. single instruction stream, multiple data stream). Systemy, w których na podstawie pojedynczego strumienia rozkazów wykonuje się jednocześnie operacje (te same rozkazy) na różnych danych; na przykład procesory wektorowe. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 60 Architektury równoległe 3. MISD (ang. multiple instruction stream, single data stream). Sztucznie dodana klasa dla kompletności klasyfikacji; nie ma odpowiednich przykładów takiej architektury. 4. MIMD (ang. multiple instruction stream, multiple data stream). Systemy wieloprocesorowe, w których co najmniej dwa procesory wykonują oddzielne strumienie rozkazów operujące na różnych danych. Przyjrzymy się teraz bliżej tym czterem klasom. 5.2.1 SISD Jest to najbardziej rozpowszechniona klasa procesorów, w której zasadniczo nie mamy do czynienia z równoległością. Równoległość w tych procesorach występuje pod postacią przetwarzania potokowego rozkazów (instrukcji). Zasadniczą ideą jest przedstawienie cyklu wykonania każdego rozkazu jako ciągu niezależnych mikrooperacji. Przyjrzyjmy się poniższemu przykładowi W procesorach typu SISD nie uzyskujemy równoległości wykonania (tj. nie mamy do czynienia z równoległym wykonaniem kilku akcji), ale równoległość przetwarzania. Największą przeszkodę w efektywnym przetwarzaniu potokowym stanowią instrukcje skoku. Przyjrzyjmy się poniższemu przykładowi 5.2.2 SIMD Wyobraźmy sobie, że mamy do dodania dwa 10-cio elementowe wektory złożone z liczb rzeczywistych a = [a1 , . . . , a10 ] b = [b1 , . . . , b10 ] a wynik będziemy przechowywać w wektorze c = [c1 , . . . , c10 ]. Naturalny jest następujący sposobem zapisu takiego działania c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 5.3 Klasyfikacja architektur równoległych według Duncana 5.2.3 61 MIMD Systemy typu MIMD składają się z wielu jednostek przetwarzających działających niezależnie od pozostałych. Pozwala to na wykonywanie różnych zestawów instrukcji na różnych danych w tym samym czasie. Jest to najbardziej różnorodna spośród wszystkich kategorii Flynna. Obejmuje bowiem zarówno maszyny złożone z wielu procesorów i niezależnych ukłądów pamięci specjalnie zaprojektowanych do przetwarzania równoległego jak i sieć stacji roboczych połączonych siecią lokalną. Rozwijająca się wciąż komunikacja sieciowa wsparta rozwojem oprogramowania pozwalającego na zdalne wykonywanie procedur i programów (np. RPC - ang. remote procedure call, PVM - ang. parallel virtual machine) a także języków, które w znacznej mierze ułatwiają pisanie aplikacji rozproszonych i wielowątkowych (np. Ada), pozwalają niejednokrotnie traktować zespół, nawet jednoprocesorowych a więc typu SISD, stacji roboczych jako system typu MIMD. Zauważmy, że do tej kategori zaliczymy zarówno maszynę dwuprocesorową w której każdy procesor wykonuje w tym samym czasie inny program jak i maszynę, w której w tym samym czasie dwa procesory wykonują różne instrukcje tego samego programu. W pierwszym przypadku mówimy o paraleriźmie (równoległości) na poziomie zadan (ang. job level parallelism) w drugim zaś (niewątpliwie dużo bardziej złożonym) o paraleriźmie na poziomie instrukcji tego samego programu (ang. instruction level parallelism). 5.3 Klasyfikacja architektur równoległych według Duncana Niestety schemat klasyfikacji przedstawiony w rozdziale 5.2 nie uwzględnia najnowszych dokonań w dziedzinie architektur równoległych. Klasyfikacja Duncana [1] została opracowana jako próba objęcia erchitektur nie mieszczących sie w podziale Flynna a także w celu wyłączenia architektur będących w zasadzie szeregowymi, ale wykorzystujących niskopoziomowe mechanizmy równoległe. Podział Duncana zachowuje częściowo terminologię Flynna i wprowadza rozróżnienie architektur wykonujących operacje synchronicznie i asynchronicznie. Poniżej przedstawiamy klasyfikację zaproponowaną przez Duncana: 1. Synchroniczne (a) Wektorowe (b) SIMD c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 62 Architektury równoległe i. Macierze procesorów ii. Pamięć asocjacyjna (c) Systoliczne 2. MIMD (a) Pamięć rozproszona (b) Pamięć wspólna 3. Paradygmat MIMD (a) MIMD/SIMD (b) Przepływ danych (c) Redukcja (d) Czoło fali Poniżej opiszemy te z kategorii, których znaczenie nie jest intuicyjnie jasne lub odbiega od znaczenia nadanego przez taksonomie Flynn’a. 5.3.1 Wektorowe Znaczenie ”wektorowa”w odniesieniu do maszyny, przy wykorzystywaniu taksonomi Duncana jest odmienne od znaczenia ”wektorowyńadanego przez taksonomię Flynn’a przy opisie architektury typu SIMD. Otóż procesor wektorowy (ang. vector processors), składa się wielu, połączonych w potok i działających równolegle jednostek funkcjonalnych odpowiedzialnych za wykonanie operacji arytmetyczno-logicznej zarówno na skalarach jak i wektorach. Realizacja postulatu równoległości w tych procesorach odbywa się przez równoległą (jednoczesną) pracę jednostek funkcjonalnych przetwarzających sekwencyjnie kolejne elementy wektora. Zrozumienie tej idei ułatwić może rysunek ??. Hmmm... Wątpliwa równoległość :) 5.3.2 SIMD W taksonomi Duncana architektura typu SIMD, której ideę przedstawiono w podrozdziale 5.2.2 dzielona jest na dwie podkategorie: macierze procesorów (ang. processor array architectures) oraz pamięć asosjacyjna (ang. associative memory prosessor architectures). c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 5.3 Klasyfikacja architektur równoległych według Duncana 5.3.3 63 Systoliczne Architektura systoliczna1 (ang. systolic architectures) zaproponowna została na początku lat ’80 przez H. T. Kunga z Carnegie Mellon University i miała być rozwiązaniem dla systemów, które muszą dzielić swoją wydajność pomiędzy obliczenia i liczne operacje wejścia-wyjścia. W systemach systolicznych dane przepływają z pamięci komputera w sposób rytmiczny: po pobraniu z pamięci dane przechodzą przez wiele elementów przetwarzania zanim trafią z powrotem do pamięci – podobnie jak krew krążąca w układzie krwionośnym wypływając i wpływając do serca. Each processor at each step takes in data from one or more neighbours (e.g. North and West), processes it and, in the next step, outputs results in the opposite direction (South and East). An example of a systolic algorithm might be matrix multiplication. One matrix is fed in a row at a time from the top of the array and is passed down the array, the other matrix is fed in a column at a time from the left hand side of the array and passes from left to right. Dummy values are then passed in until each processor has seen one whole row and one whole column. At this point, the result of the multiplication is stored in the array and can now be output a row or a column at a time, flowing down or across the array. 5.3.4 MIMD z pamięcią rozproszoną Zwyczajnie: MIMD, który ma pamięć rozproszoną. 5.3.5 MIMD z pamięcią wspólną Zwyczajnie: MIMD, który ma pamięć wspólną. 5.3.6 MIMD/SIMD 5.3.7 Przepływ danych Non-Uniform Memory Access and Non-Uniform Memory Architecture (NUMA) is a computer memory design used in multiprocessors, where the memory access time depends on the memory location relative to a processor. 1 Termin systoliczny zapożyczony zapewne został z medycyny, gdzie oznacza skurczowy. Oznacza ciśnienie krwi jakie osiągane jset podczas skurczu serca. Chyba, bo ja tam słaby z medycyny jestem :) c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 64 Architektury równoległe Under NUMA, a processor can access its own local memory faster than nonlocal memory, that is, memory local to another processor or memory shared between processors. Symmetric Multiprocessing, or SMP, is a multiprocessor computer architecture where two or more identical processors are connected to a single shared main memory. Most common multiprocessor systems today use an SMP architecture. SMP systems allow any processor to work on any task no matter where the data for that task is located in memory; with proper operating system support, SMP systems can easily move tasks between processors to balance the workload efficiently. On the downside, memory is much slower than the processors accessing them, and even single-processor machines tend to spend a considerable amount of time waiting for data to arrive from memory. SMP makes this worse, as only one processor can access memory at a time; it is possible for several processors to be starved. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Rozdział 6 Errata Rozdział ten zawiera poprawki i pewne dodatki związane z [3]. 6.1 Poprawki Zapis: s. 123, w. 12 g (d) oznacza: strona 123 wiersz 12 od góry (dołu). • s. 7, w. 9 d jest: nie tyle powodu powinno być: nie tyle z powodu • s. 10, w. 12 g jest: dalszych informacji wymienionych w pozycjach bibliografii powinno być: dalszych informacji w wymienionych pozycjach bibliografii • s. 41, przykład 2.1 jest: w = ... (2.9,2.7) = (x + x0)(x + z) (2.14,2.7) = ... powinno być: w = ... (2.9,2.7) = (x + x + 0)(x + z) (2.14,2.7) = ... • s. 65, w. 4 g jest: (Q ∪ {k, t, n} × Σ) powinno być: (Q ∪ {k, t, n}) × Σ c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 66 Errata • s. 71, w. 4 d jest: mikroprocesory powinno być: mikrokontrolery • s. 76, rozdział 3.4 jest: opis nie jest wystarczająco precyzyjny i nie odpowiada rysunkowi powinno być: proponujemy zdanie: „ Zasadniczo w procesorze 8086 wyróżnia się . . . .” zastąpić zdaniem: „Zasadniczo w procesorze 8086 wyróżnia się dwa główne elementy: układ wykonawczy i układ sterowania magistrali.”. Ponadto przy opisie elementów składowych układu wykonawczego dodać: EU – jednostka wykonawcza (ang. execution unit), odpowiada za wykonanie rozkazu; • s. 106, 3 wiersz tabeli przejść z zadania 6 a) w kolumnie: kierunek ruchu głowicy jest: → powinno być: ← • s. 127, w. 7 d jest: odwołanie od konkretnego powinno być: odwołanie do konkretnego • s. 132, źle sformatowany pseudokod instrukcji pętli do-while i while powinno być: do begin ... ciąg instrukcji powtarzanych dopóki warunek jest spełniony end while(warunek) while(warunek) begin ... ciąg instrukcji powtarzanych dopóki warunek jest spełniony end • s. 143, przykład 5.6 powinno być: c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 6.2 Uzupełnienie literatury 67 fib_r (n) begin if (n=1) then begin fib_r := 1; end if (n=0) then begin fib_r := 1; end w := fib_r(n-1)+fib_r(n-2); fib_r := w; end • s. 246, odpowiedzi do zadania 8 dla podpunktów a), b), e), f) oraz j) powinny być następujące: a) b) e) f) j) 6.2 C99 2A5 3BC 910 40C → → → → → 2853 575 815 2084 844 Uzupełnienie literatury c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 68 Errata c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007 Bibliografia [1] R.A. Duncan, Survey of Parallel Computer Architectures, IEEE Computer, vol. 23, no. 2, February 1990, s. 5-16. [2] Michael J. Flynn, Kevin W. Rudd, Parallel Architectures, In ACM Computer Surveys, March 1996 (materiały znalezione w Internecie). [3] Piotr Fulmański, Ścibór Sobieski, Wstęp do informatyki. Podręcznik, Wydawnictwo UŁ, 2005. [4] H.-O. Peitgen, H. Jurgens, D. Saupe, Granice haosu. Fraktale, tom I, Wydawnictwo Naukowe PWN, Warszawa, 1997. [5] Cezary Zieliński, Podstawy projektowania układów cyfrowych, Wydawnictwo Naukowe PWN, Warszawa, 2003. c 2005 – 2006 by P. Fulmański, Uniwersytet Łódzki. Wersja 0.1 z dnia: 30 listopada 2007