Liczby zespolone w języku C (cz.3)
Transkrypt
Liczby zespolone w języku C (cz.3)
Katedra Elektrotechniki Teoretycznej i Informatyki wykłady 4 - sem.III Dr inż. M. Czyżak Język ANSI C – wskaźniki Wyrażenie *px ma różny sens w zależności od tego czy występuje po lewej czy też po prawej stronie instrukcji podstawienia. Dla następujących definicji i instrukcji int x=5,y, *px; px=&x; w instrukcji y=*px; wyrażenie *px reprezentuje zawartość komórki wskazywanej przez px, czyli komórki x (jest to 5). Natomiast w instrukcji *px=15; wyrażenie *px reprezentuje adres pamięci ( zmienną), pod który można wpisać jakąś wartość. Język ANSI C – wskaźniki L-wartości ( ang. lvalue) i R-wartości W języku ANSI C zmienna jest nazwanym obszarem pamięci; L-wartość jest wyrażeniem reprezentującym pewien obszar pamięci. Przykładem L-wartości jest identyfikator o odpowiednim typie i klasie pamięci. Niektóre operatory jako wynik swojego zastosowania dają L-wartość, np. jeżeli W jest wyrażeniem wskaźnikowym, to *W jest L-wartością odnoszącą się do obiektu wskazywanego przez W. Określenie L-wartość wywodzi się od instrukcji przypisania W1=W2; w której lewy argument musi L-wartością ( reprezentować pewną lokację w pamięci). Stosując poszczególne operatory należy zważać czy zastosowanie danego operatora daje w wyniku L-wartość. Język ANSI C – wskaźniki Przykład. (L-wartość) int x=0; int *wski; x=x+1; L-wartość (lokacja pamięci) wski = &x; /* wskaźnik wski wskazuje na x */ *wski = *wski +1; L-wartość Język ANSI C – wskaźniki Arytmetyka na wskaźnikach W językach C i C++ stosując wskaźniki można posługiwać się tzw. ograniczoną arytmetyką na wskaźnikach. Oznacza to, że można stosować niektóre operacje arytmetyczne, by obliczyć odpowiedni wskaźnik. Należy jednak w każdym przypadku zważać na to, co może oznaczać wynik danego działania. Dla wskaźników można stosować następujące operacje wskaźnikowe: Język ANSI C – wskaźniki Działania arytmetyczne na wskaźnikach Na wskaźnikach wskazujących na ten sam typ można dokonywać następujących operacji: - inkrementacji (++) ( zwiększania) - dekrementacji (--) ( zmniejszania) - dodawania do wskaźnika liczby całkowitej - odejmowania od wskaźnika liczby całkowitej - odejmowania wskaźników od siebie - porównywania dwóch wskaźników. Język ANSI C – wskaźniki Inkrementacja wskaźnika Jeżeli wskaźnik wsk do pewnego typu wskazuje na pewną komórkę pamięci, to wyrażenie wsk++ wskazuje na komórkę o adresie wsk+sizeof(typ). Przykład. Inkrementacja wskaźników do int . int *wsk,x; wsk wsk=&x; wsk++; x wsk++ Język ANSI C – wskaźniki Dekrementacja wskaźnika Jeżeli wskaźnik wsk do pewnego typu wskazuje na pewną komórkę pamięci, to wyrażenie wsk-- wskazuje na komórkę o adresie wsk-sizeof(typ). Przykład. Dekrementacja wskaźnika do int int *wsk,x; wsk-- wsk wsk=&x; wsk--; x Język ANSI C – wskaźniki Dodawanie do wskaźnika liczby całkowitej Jeżeli wskaźnik wsk do pewnego typu wskazuje na pewną komórkę pamięci to wyrażenie wsk+liczba wskazuje na komórkę o adresie wsk+liczba*sizeof(typ). Odejmowanie od wskaźnika liczby całkowitej Jeżeli wskaźnik wsk do pewnego typu wskazuje na pewną komórkę pamięci to wyrażenie wsk-liczba wskazuje na komórkę o adresie wsk-liczba*sizeof(typ). Język ANSI C – wskaźniki Odejmowanie wskaźników Jeżeli dane są dwa wskaźniki wsk1 i wsk2,do tego samego typu Type, to po wykonaniu instrukcji diff= wsk2 - wsk1; diff ma wartość dodatnią, jeżeli wsk2 wskazuje na wyższy adres, i ma wartość równą liczbie elementów typu Type, które można umieścić między adresami komórek pamięci wskazywanych przez wsk1 i wsk2. Jeśli wsk2 wskazuje na adres niższy, diff ma wartość ujemną, a interpretacja jest podobna. Język ANSI C – wskaźniki Porównywanie wskaźników Jeśli wskaźniki wsk1 i wsk2 wskazują na ten sam typ, to wyrażenie wsk2>wsk1 ma wartość logiczną prawda, jeżeli wsk2 wskazuje na adres wyższy i wartość fałsz, gdy na niższy. Język ANSI C – wskaźniki Przykład. L-wartości i R-wartości #include <stdio.h> #include<stdlib.h> int main(int argc, char* argv[]) { int j=5,*wski,i=10; wski=&i; *wski=j; // *wski jest L-value (L-wartoscią) //++ * wski=j; // L-value required ( wymagana //L-wartosc), wyrażenie nie jest //L-wartością * ++wski=j; // *++wski jest L-value Język ANSI C – wskaźniki Przykład. L-wartości i R-wartości (c.d) // (*wski) ++=j; // L-value required // wymagana L-wartość *(wski ++)=j; system("pause"); return 0; } // L-value (L-wartość) Język ANSI C – wskaźniki Wskaźniki i tablice Nazwa tablicy w C jest stałym wskaźnikiem do pierwszego elementu tablicy. Np. jeżeli stworzymy definicje int a[5]; int *pa; i zastosujemy instrukcję pa=a; to wskaźnik pa będzie wskazywał na a[0], czyli pierwszy element tablicy a. Stosując wskaźniki można wykonać te same operacje na tablicach, co przy użyciu indeksowania. Język ANSI C – wskaźniki Przykład. Proste działania na tablicach przy użyciu wskaźników #include <stdio.h> int main() { int a[5]; int *pa,i; pa=a; // przypisanie wskaźnikowi pa adresu elementu a[0] *pa=10; //zapis wartości 10 do a[0] pa++; //zwiększenie wskaźnika, wskazuje on teraz na a[1] *pa=20; // zapis wartości 2 do a[1]; pa=pa+1; // wskaźnik wskazuje na element a[2] for (i=2; i<5; i++){ printf("\n Podaj a[%d]=",i); scanf("%d",pa); pa++; } pa=a; // ustawienie wskaźnika na początek tablicy // alternatywnie pa= pa-5 for (i=0;i<5;i++) printf("\n a[%d]=%d", i,*pa++); printf("\n"); system("PAUSE");} Język ANSI C – wskaźniki Przyklad. Program wczytujący tablicę dwuwymiarową przy zastosowaniu wskaźników #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int tab[3][3]; int *p; p=&tab[0][0]; int i,j; for (i=0;i<3;i++) for (j=0;j<3;j++) { printf("\n Podaj element [%d}[%d}=",i,j); scanf("%d",p+j+i*3); } for (i=0;i<3;i++) { for (j=0;j<3;j++) printf(" system("PAUSE"); %d",*(p+j+i*3)); printf("\n"); } Liczby zespolone w języku C (cz.1) Standard ISO C99 wprowadza wsparcie dla liczb zespolonych w języku C. Jest to realizowane przez wprowadzenie słów kluczowych _Complex i _Imaginary oraz nowych kwalifikatorów complex, _Complex_I, imaginary, _Imaginary_I. Mają one następujące znaczenie - complex – identyfikator służący do tworzenia definicji typu zespolonego - _Complex_I – identyfikator reprezentujący i − 1 - imaginary – identyfikator służący definicji typu urojonego - _Imaginary_I – identyfikator reprezentujący− 1i typu urojonego Nie wszystkie są obsługiwane przez przez kompilator DevC++. Obsługuje on _Complex, _Complex_I oraz complex ( jeśli włączono plik complex.h ) Plik ten umożliwia również stosowanie identyfikatora I jako −1 . Liczby zespolone w języku C (cz.2) Przykład. Zapis liczb zespolonych w programie C. (zastosowanie I i _Complex_I) 3.0 +4.0 i 3.0+ 4.0 * I 3.0 +4.0 i 3.0+ 4.0 * _Complex_I Liczby zespolone w języku C (cz.3) Typy zespolone Przykłady definicji zmiennych typów zespolonych. float _Complex z1; // części rzeczywista i urojona są typu float float complex z2; double complex double _Complex z3; // części rzeczywista i urojona są typu double w[2]={ 1+2*I , -3+4*I};// definicja tablicy // long double _Complex z4; long double z5; complex z inicjalizacją Na wartościach typów zespolonych można wykonywać te same działania arytmetyczne co na typach rzeczywistych ( +,-,*,/) Liczby zespolone w języku C (cz.4) W C99 wprowadzono szereg arytmetycznych funkcji standardowych umożliwiających realizację różnego rodzaju operacji na danych zespolonych. Poniżej podano cztery wybrane funkcje: cabs() - oblicza wartość modułu liczby zespolonej carg() - oblicza kąt fazowy creal() - wyznacza część rzeczywistą liczby zespolonej cimag() - wyznacza część urojoną liczby zespolonej Oprócz tych funkcji istnieją specjalne konstrukcje, które umożliwiają wczytywanie liczb zespolonych jak również wyznaczanie części rzeczywistej i części urojonej. Wyrażenie __ real__ zmiennaZespolona reprezentuje część rzeczywistą zmiennej zmiennaZespolona ( __ to podwójne podkreślenie) Wyrażenie __ imag__ zmiennaZespolona reprezentuje część rzeczywistą zmiennej zmiennaZespolona Poniżej w programie zastosowano wczytywanie i drukowanie wartości zespolonych z użyciem tych konstrukcji. Liczby zespolone w języku C (cz.5) #include <complex.h> #include <stdio.h> int main(int argc, char *argv[]){ double _Complex z1,z2;// pierwszy sposób definicji double complex z3,z4;// drugi sposób definicji double complex z5=100+200*I;// definicja z inicjalizacją // Przypisywanie wartości liczbom zespolonym z1=2+3*_Complex_I;// 2+3i z2=4+6*I; // 4+6i z3=z1+z2; // sumowanie liczb zespolonych // podobnie odejmowanie, mnozenie i dzielenie printf("\n z5=%f+j%f",creal(z5),cimag(z5)); // funkcja creal(z) wyznacza część rzeczywistą liczby Liczby zespolone w języku C (cz.6) // wczytywanie liczby zespolonej i drukowanie printf("\n z1="); scanf("%lf %lf", &(__real__ z1),&(__imag__ z1)); // drukowanie liczby zespolonej (sposob 1) printf("\n z1=%lf %lf", creal(z1),cimag(z1)); // drukowanie liczby zespolonej (sposob 2) printf("\n z1=%lf %lf", __real__ z1,__imag__ z1); Liczby zespolone w języku C (cz.7) Przykład. Napisać program realizujący transformacje gwiazda-trójkąt i trójkąt-gwiazda dla zadanych impedancji wczytywanych z wejścia, wczytywać z klawiatury kierunek transformacji. 1 1 Z1 Z2 Z12 Z3 Z13 2 3 Z23 2 Z Z + Z 2 Z 3 + Z1 Z 2 Z12 = 1 3 Z3 Z 23 = Z1Z 2 + Z1Z 3 + Z 2 Z 3 Z1 3 Z13 = Z1Z 2 + Z 2 Z 3 + Z1Z 3 Z2 Liczby zespolone w języku C (cz.8) Przykład. Napisać program obliczający prąd w obwodzie dla zadanego napięcia wejściowego i zadanych impedancji, następnie zmodyfikować program, tak aby dane były wprowadzane z klawiatury. i 3 5-j3 2+j3 150ej0 8+j2.5 ~ 10+j6 1 5+3j 3-j2 2 Liczby zespolone w języku C (cz.9) X ( jω ) K ( jω ) Y ( jω ) K ( jω ) = X ( jω ) K ( jω ) - transmitacja zespolona Y ( jω ) Liczby zespolone w języku C (cz.10) K ( jω ) = K ( jω ) ⋅ e K ( jω ) θ (ω ) jθ ( ω ) -charakterystyka amplitudowa -charakterystyka fazowa W decybelach 20 log K ( jω ) Liczby zespolone w języku C (cz.11) Przykład.Obliczanie charakterystyki amplitudowej filtru. #include <stdio.h> #include <stdlib.h> #include <complex.h> int main () { double complex z1,z2,z3; double complex p1,p2,p3,p4,K_jOmega; double absK_jOmega,absK_jOmega1; double Omega=0; int i; p1=-0.92+0.38*I;//sprzężone bieguny transmitancji p2=-0.92-0.38*I; p3=-0.38+0.92*I; p4=-0.38-0.92*I; Liczby zespolone w języku C (cz.12) // Obliczanie modulu charakterystyki amplitudowej for (i=0;i<200;i++) { K_jOmega=(Omega*I+p1)*(Omega*I+p2)\ *(Omega*I+p3)*(Omega*I+p4); K_jOmega=1/K_jOmega; // obliczanie absK_jOmega=20*log10(sqrt(creal(K_jOmega)*\ creal(K_jOmega)+cimag(K_jOmega)*cimag(K_jOmega))); // uzycie funkcji obliczajacej modul liczby zespolonej (drugi sposób) absK_jOmega=20*log10(cabs(K_jOmega)); Liczby zespolone w języku C (cz.13) // Obliczanie modulu charakterystyki amplitudowej (c.d) printf("\n Omega=%6.2f abs_K(jOmega)=%6.2f db",\ Omega,absK_jOmega); Omega=Omega+0.1; getch(); } return 0; }