Zad. 5: Układ równań liniowych liczb zespolonych 1 Cel ćwiczenia Wykształcenie zdolności abstrahowania operacji arytmetycznych od konkretnych typów. Unaocznienie problemów związanych z programowaniem uogólnionym i potencjalnych zalet takiego podejścia. Tworzenie diagramów klas i diagramów czynności z wykorzystaniem programu dia. Tworzenie dokumentacji z wykorzystaniem systemu doxygen. 2 Program zajęć Ocena realizacji zadania z poprzedniego laboratorium ocenie podlega poprawność realizacji zadania, styl pisania programu oraz opisy. Ocena przygotowania do zajęć realizacja modułu liczb zespolonych (patrz podrozdział 5.1). Modyfikacja programu wg wskazań osoby prowadzacej ocenie będzie podlegała poprawność realizacji modyfikacji. Pracę nad modyfikacją programu (wszystkie operacje muszą być wykonywane na kopii) należy rozpocząć już w trakcie pierwszej fazy laboratorium, gdyż prowadzący nie będzie w stanie ocenić wcześniejszego programu wszystkim jednocześnie. Realizacja wstępnej fazy prac nad nowym zadaniem w ramach wstępnej realizacji zadania należy rozbudować klasę liczb zespolonych o niezbędne dodatkowe metody i przeciążenia. Ocena realizacji wstępnej fazy zadania 3 Opis zadania programowego Należy przerobić program rozwiązujący układ równań z poprzedniego zadania, tak aby działał na liczbach zespolonych. W tym celu należy stworzyć dodatkowy moduł, który będzie zawierał definicję klasy liczb zespolonych oraz definicje odpowiednich metod. Niniejsze zadanie jest swego rodzaju sprawdzianem poprawności przyjętych wcześniej koncepcji. Im były one lepsze tym mniej problemów będzie nastręczała zamiana typów liczb, na których działa program. 3.1 Działanie programu Tak jak we wcześniejszym zadaniu, na wejście programu podawana jest macierz współczynników równania oraz wektor wyrazów wolnych. Podawane są one w postaci transponowanej. Dla przykładu rozważmy układ równań: 2x 1 + (2 + i)x 2 + 2ix 3 = 5 + 2i x 1 + 2x 2 + 2x 3 = 4 + 4i x 1 + 3x 2 + x 3 = 4 + 4i 1
Tak więc dla tego problemu złożenie macierzy A i wektora b ma postać: 2 2 + i 2 5 + 2i [A b] = 1 2 2 4 + 4i 1 3 1 4 + 4i Postać transponowana to: [A b] T = 2 1 1 2 + i 2 3 2 2 1 5 + 2i 4 + 4i 4 + 4i Dla ułatwienia operacji czytania, zakładamy, że liczby zespolone podawane są w nawiasach klamrowych. Tak więc zamiast zapisu: Stosować będziemy zapis: 2 + 4.2i {2+4.2i} Kolejnym ułatwieniem jest zapisywanie liczby w pełnej notacji niezależnie od tego czy część rzeczywista lub urojona jest zerowa lub nie, np. 2 -> {2+0i}, 3i -> {0+3i}, i -> {0+1i}. Aby uprościć sobie pracę, warto zapisać dane w pliku i później czytać je z niego poprzez przekierowanie go na wejście standardowe programu. Taki sposób postępowania przedstawiony jest poniżej. jkowalsk@noxon: rozwiazanie> cat rownanie_liniowe_zesp.dat {2+0i} {1+0i} {1+0i} {2+1i} {2+0i} {3+0i} {2+0i} {2+0i} {1+0i} {5+2i} {4+4i} {4+4i} jkowalsk@noxon: rozwiazanie>./uklad_rownan_zesp < rownanie_liniowe_zesp.dat Macierz A^T: {2+0i} {1+0i} {1+0i} {2+1i} {2+0i} {3+0i} {2+0i} {2+0i} {1+0i} Wektor wyrazow wolnych b: {5+2i} {4+4i} {4+4i} Rozwiazanie x = (x1, x2, x3): {4+0i} {0+1i} {0+1i} 2
Wektor bledu: Ax-b = ({4.76e-7+1.2e-8} {2.3e-7+1.45e-9i} {0-0i} {1.31e-8+0i}) Dlugosc wektora bledu: Ax-b = 5.289517e-07 jkowalsk@noxon: rozwiazanie>_ Uwaga: Dane o błędzie mają jedynie charakter poglądowy. Nie są to faktycznie wyliczone wartości. Ułożenie znaków w linii w przypadku wyświetlania macierzy, nie musi być idealnie równe, aby jeden wiersz długością pasował do drugiego. Przedstawiony przykład należy uznać za obligatoryjny (dla wariantu podstawowego), jeśli chodzi o wyświetlane informacje. 3.2 Materiały pomocnicze Plik zawierający przykładowe dane znajduje się w katalogu bk/edu/kpo/zad/z5. W katalogu tym znajduje się również plik nagłówkowy do modułu liczb zespolonych, który należy zdefiniować w ramach przygotowania do zajęć (patrz rozdział 4.1). 4 Zalecenia (ważne) Istniejące konstrukcje w języku C++ pozwalają na niejawne konwersje typów. Jeżeli mechanizmy nie są świadomie stosowane lub nie są dobrze zrozumiane, to mogą prowadzić do błędów działania programu, które będą bardzo trudne do zdiagnozowania. Aby tego uniknąć należy zastosować zalecenia przedstawione poniżej. Nie zaleca się definiowanie konstruktora jednoargumentowego postaci: LZespolona::LZespolona(float r); Zalecane jest natomiast zdefiniowanie konstruktora bezparametrycznego oraz dwuargumentowego, tzn. LZespolona::LZespolona(); LZespolona::LZespolona(float r, float i); 4.1 Wymagania co do konstrukcji programu Oprócz wymagań sformułowanych w opisie zadania należy uwzględnić uwarunkowania przedstawione poniżej. Program musi zachować strukturę modułową i odpowiednią strukturę kartotek. O ile będzie to konieczne, należy zmodyfikować plik Makefile (np. gdy dodany zostanie nowy moduł - np. moduł liczb zespolonych). Wszystkie metody, które nie zmieniają stanu obiektu, na którym działają, powinny być metodami typu const. Wszystkie klasy i metody powinny być opisane. Oprócz tego pozostają w mocy wszystkie wcześniejsze wymagania dotyczące struktury katalogów, pliku Makefile, modułowej struktury programu, jak też opisów. 3
4.2 Rozszerzenia nieobowiazkowe Proponuje się, aby odpowiednio rozbudować przeciążenie operatora >> dla wczytywana liczb zespolonych ze strumienia wejściowego, tak aby można było wczytywać je w uproszonej notacji, tzn. bez części rzeczywistej, jeśli jest równa 0 i odpowiednio tak samo w przypadku części urojonej, z pominięciem liczby przy oznaczeniu części urojonej, gdy jest ona równa 1 lub 1, np. {5i} {10} {2-i} {1+i} {i} {-i} 5 Przygotowanie do zajęć 5.1 Tydzień 0 Należy przygotować zaczątek modułu liczb zespolonych. Plik nagłówkowy z wymienionym minimalnym zestawem metod i przeciążeń operatorów, które należy oprogramować znajduje się na panamincie i diablo w katalogu w lokalizacji: ~bk/edu/kpo/zad/z5/lzespolona/lzespolona.hh Zawartość tego pliku to definicja klas LZespolona oraz zapowiedzi definicji metod jak poniżej: #ifndef LZESPOLONA_HH #define LZESPOLONA_HH #include <iostream> class LZespolona { double _re; double _im; }; public: LZespolona(); double Re() const; double& Re(); double Im() const; double& Im(); LZespolona operator + (const LZespolona& Arg2) const; LZespolona operator * (const LZespolona& Arg2) const; std::ostream& operator << ( std::ostream& StrmWy, const LZespolona& WyswietlanaLiczba ); #endif Należy stworzyć własny moduł lzespolna.cpp, w którym znajdą się definicje metod oraz przeciążenia operatora «dla wyświetlania liczby na strumieniu wyjściowym. Następnie należy przetestować poprawność konstrukcji modułu kompilując go i konsolidując plikiem typu object znajdującym się na panamincie w lokalizacji: 4
~bk/edu/kpo/zad/z5/test/test-lzespolona.o Przykład instrukcji (dla panaminta): g++ -g -Wall -std=c++11 -pedantic -I/home/bk/edu/kpo/zad/z5/lzespolona lzespolona.cpp\ /home/bk/edu/kpo/zad/test/test-lzespolona.o Aby nie wpisywać za każdym razem tej instrukcji, zalecane jest stworzenie sobie odpowiedniego pliku Makefile, Dla ułatwienia w kartotece bk/edu/kpo/zad/z5/zalazek został umieszczony zalążek modułu wraz z odpowiednim plikiem Makefile. Kartotekę tę należy przekopiować do swojej kartoteki. Utworzony program po uruchomieniu testuje poprawność implementacji poszczególnych metod i wypisuje odpowiedni wynik testu. Poniżej przedstawiona jest jego przykładowa postać: jkowalsk>./a.out Test wyswietlenia wartosci: {5+2i}... Dobrze! Test realizacji operacji: {4+2i} + {3+2i} = {7+4i}... Dobrze! Test realizacji operacji: {1+2i} * {3+2i} = {-1+7i}... Dobrze! jkowalsk> _ Test należy przeprowadzić w obecności prowadzącego. 5.2 Tydzień 1 Klasa LZespolona powinna zawierać definicje wszystkich niezbędnych metod. Należy przygotować diagram klas i diagram czynności w wersji elektronicznej z wykorzystaniem programu dia. Materiały do nauki posługiwaniem się programem dia dostępne są na stronie kursu. Ponadto należy odpowiednio skonfigurować i utworzyć dokumentację w wersji elektronicznej za pomocą programu doxygen. W dokumentacji tej powinny być umieszczone już rysunki diagramów. Należy to zrobić na podstawie przykładów demonstrowanych w materiałach do wykładu. 5.3 Tydzień 2 Rozliczenie się z gotowego programu i rozpoczęcie następnego zadania (tydzień 0 dla zadania nr 6). 5