6. INSTRUKCJA PRZYPISANIA
6.1. Składnia i działanie
Instrukcja przypisania to jedna z najczęściej używanych instrukcji. Jej ogólna postać jest następująca:
Nazwa_zmiennej := Wyrażenie;
Po lewej stronie instrukcji może wystąpić wyłącznie nazwa zmiennej. Po niej mamy operator przypisania „:=”, a po prawej stronie instrukcji - jakieś wyrażenie. Wyrażenie umieszczone po prawej stronie instrukcji może być stałą jawną, nazwą stałej definiowanej, zmienną, wywołaniem funkcji lub złożonym wzorem, zawierającym wymienione elementy, połączone odpowiednimi operatorami działań. Poniżej pokazano kilka przykładów instrukcji:
X:= 0;
I:=I+1;
Delta:=Sqrt(B*B-4*A*C);
Odleglosc:=Sqrt(Sqr(X1-X2)+Sqr(Y1-Y2));
Pole_trojkata:=Podstawa*Wysokosc/2;
X:=Pi;
A:=Abs(A);
Nie należy mylić operatora przypisania ':=' ze znakiem równości '='. Operator przypisania jest symbolem operacji przesyłania danej w kierunku od prawej do lewej strony instrukcji. Operacja przypisania składa się z dwóch faz:
Zostaje obliczona wartość wyrażenia po prawej stronie instrukcji
Wynik zostaje zapamiętany w zmiennej, której nazwa jest po lewej stronie instrukcji. (Poprzednia wartość tej zmiennej zostaje wymazana).
Przykład przebiegu dwóch faz działania instrukcji pokazano na rysunku 6.1.
const K:Byte=3;
begin K:=K+1; end.
|
Faza 1
K+1=3+1=4
Faza 2
|
Rys. 6.1. Działanie instrukcji przypisania K:=K+1
W programie z przykładu 6.1 zastosowano trzy instrukcje przypisania do zamiany miejscami aktualnych wartości dwóch zmiennych. Zamiana taka nie jest możliwa bez pomocniczej zmiennej, nazwanej tu Kopia. Zachęcamy do samodzielnej analizy tego programu, w czym pomagają umieszczone w nim komentarze.
Przykład 6.1. Zamiana miejscami wartości dwóch zmiennych
program Ex6_1; {Zamienia miejscami aktualne wartości zmiennych A,B.} uses Crt; var A,B,Kopia:Integer; begin Clrscr; A:=88; B:=5; Writeln('Wartosci poczatkowe:'); Writeln(' A=',A,', B=',B);
{Zamiana miejscami} Kopia:=A; {A=88, Kopia=88} A:=B; {B=5, A=5} B:=Kopia; {Kopia=88, B=88}
Writeln; Writeln('Wartosci po zamianie:'); Writeln(' A=',A,', B=',B); Readln; end.
|
6.2. Zgodność typów w sensie przypisania
Wykonanie instrukcji przypisania:
L:=P;
wymaga, by typ zmiennej L był zgodny z typem wyrażenia P. Jednak nie oznacza to, że zgodność występuje tylko wtedy, gdy typy L i P są identyczne. Przypisanie jest dozwolone, kiedy:
L i P mają identyczny typ.
L i P należą do grupy typów porządkowych i jednocześnie wszystkie wartości P należą do zakresu możliwych wartości L.
L i P należą do grupy typów rzeczywistych i jednocześnie wartości P należą do zakresu możliwych wartości L.
L jest typu rzeczywistego, a P jest typu całkowitego.
L i P są typu łańcuchowego.
L jest typu łańcuchowego, a P jest typu znakowego.
L i P są typu zbiorowego i jednocześnie wszystkie elementy P są w zakresie możliwych wartości L.
W przypadku niezgodności typów, w czasie kompilowania programu źródłowego wystąpi błąd kompilacji z komunikatem:
Error 26: Type mismatch.
6.3. Zastosowanie instrukcji przypisania do obliczania wartości wyrażeń
Ponieważ po prawej stronie instrukcji przypisania może wystąpić dowolne wyrażenie, które w pierwszej fazie działania instrukcji jest obliczane, a w drugiej fazie - jego wartość zostaje zapamiętana w odpowiedniej zmiennej, przydatność tej instrukcji do obliczeń jest oczywista. Do konstrukcji wyrażeń stosuje się ogólnie znane operatory arytmetyczne, zestawione w tabeli 6.1. Umieszczono w niej także operatory relacyjne i logiczne, które zostaną dokładniej omówione w rozdziale 7.
Tabela 6.1 Ważniejsze operatory Turbo Pascala
Symbol |
Operacja |
Typy argumentów |
Typ wyniku |
Operatory arytmetyczne (dwa pierwsze są jednoargumentowe) |
|||
+ - |
Identyczność znaku Zmiana znaku |
Rzeczywisty/całkowity Rzeczywisty/całkowity |
Rzeczywisty/całkowity Rzeczywisty/całkowity |
+ - * / div mod |
Dodawanie Odejmowanie Mnożenie Dzielenie Dzielenie całkowite Daje resztę z dzielenia |
Rzeczywiste/całkowite Rzeczywiste/całkowite Rzeczywiste/całkowite Rzeczywiste/całkowite Całkowite Całkowite |
Rzeczywisty/całkowity Rzeczywisty/całkowity Rzeczywisty/całkowity Rzeczywisty Całkowity Całkowity |
Operatory logiczne |
|||
not and or xor |
Negacja Koniunkcja Alternatywa Alternatywa wyłączająca |
Boolean Boolean Boolean Boolean |
Boolean Boolean Boolean Boolean |
Operatory relacyjne |
|||
= <> < > <= >= |
Równy Nierówny Mniejszy Większy Nie większy Nie mniejszy |
Liczby/string/Char/set of Liczby/string/Char/set of Liczby/string/Char Liczby/string/Char Liczby/string/Char Liczby/string/Char |
Boolean Boolean Boolean Boolean Boolean Boolean |
in
<= >= |
Jest elementem zbioru
Jest podzbiorem Jest nadzbiorem |
Lewy: typ porządkowy, prawy: set of set of set of |
Boolean
Boolean Boolean |
Pisząc wyrażenia, musimy pamiętać, że pomiędzy operatorami występuje hierarchia, decydująca o porządku wykonywania operacji (tabela 6.2). Operacje o jednakowym priorytecie wykonywane są w kolejności ich zapisu w wyrażeniu - od lewej do prawej. Jeżeli w wyrażeniu występują operatory o różnym poziomie priorytetu, to te poziomy wyznaczają porządek wykonywania działań. Na przykład w wyrażeniu: A*B+C*D mamy operator '*' o wyższym priorytecie od operatora '+'. Dlatego najpierw zostaną kolejno obliczone iloczyny A*B oraz C*D , a dopiero potem ich suma da wartość całego wyrażenia. Porządek obliczeń wynikający z priorytetów operatorów można zawsze zmienić, stosując nawiasy, na przykład pisząc: A*(B+C)*D. Pamiętajmy, że w wyrażeniach arytmetycznych można stosować tylko nawiasy zwykłe; nawiasy klamrowe służą do zaznaczania komentarzy, a kwadratowe - do zapisu indeksów i stałych typu zbiorowego.
Tabela 6.2. Priorytet operatorów
Operatory |
Priorytet |
Kategoria operatorów |
+, -, not *, /, div, mod, and +, -, or, xor =, <>, <, >, <=, >=, in |
1 (najwyższy) 2 3 4 (najniższy) |
Jednoargumentowe Multiplikatywne Addytywne Relacyjne |
Trzeba pamiętać, że jeżeli w wyrażeniu wystąpi chociażby jedna wartość rzeczywista, to wynik wyrażenia także będzie typu rzeczywistego. Zauważmy też, że wynik zwykłego dzielenia (operator `/ `) jest zawsze typu rzeczywistego, nawet w przypadku, gdy dzielna i dzielnik są całkowite i dzielą się bez reszty.
W module podstawowym System znajduje się wiele standardowych funkcji, które można wykorzystywać w wyrażeniach po prawej stronie instrukcji przypisania, lub stosować jako argumenty innych funkcji lub procedur. Listę funkcji standardowych, z podaniem ich właściwości, zawiera tabela 6.3.
Tabela 6.3. Funkcje arytmetyczne Turbo Pascala
Wywołanie |
Wielkość zwracana |
Typ argumentu |
Typ wyniku |
Arctan(x) |
Arcus tangens od x |
Dowolny liczbowy |
Real |
Sin(x) |
Sinus kąta x (x w radianach) |
Dowolny liczbowy |
Real |
Cos(x) |
Cosinus kąta x (x w radianach) |
Dowolny liczbowy |
Real |
Exp(x) |
ex |
Dowolny liczbowy |
Real |
Ln(x) |
Logarytm naturalny z x |
Liczbowy nieujemny |
Real |
Sqr(x) |
Kwadrat liczby x |
Liczbowy |
Taki, jak argumentu |
Sqrt(x) |
Pierwiastek kwadratowy z x |
Liczbowy nieujemny |
Real |
Pi |
Liczba π = 3.14159….. |
|
Real |
Random(x) |
Liczba losowa z przedziału [0..x-1] |
Word |
Word |
Random; |
Liczba losowa z przedziału [0, 1) |
|
Real |
Abs(x) |
Wartość bezwzględna x |
Dowolny liczbowy |
Taki, jak argumentu |
Frac(x) |
Część ułamkowa x |
Real |
Real |
Int(x) |
Część całkowita x |
Real |
Real |
Round(x) |
Konwersja x do typu całkowitego z zaokrągleniem |
Real |
Longint |
Trunc(x) |
Konwersja x do typu całkowitego z odrzuceniem części ułamkowej x |
Real |
Longint |
6 4. Przykłady programów wykorzystujących instrukcje przypisania.
Program pokazany w przykładzie 6.2 może w pierwszej chwili zaskakiwać pozornie nieuzasadnionym skomplikowaniem obliczeń. Ten sam rezultat można przecież uzyskać, wykonując jedną instrukcje przypisania:
Wynik:=X*X*X;
Jednak przy dużej wartości wykładnika, na przykład gdybyśmy chcieli obliczyć X100, to pozornie proste podejście byłoby nie do przyjęcia - trzeba byłoby po prawej stronie instrukcji napisać 100 identyfikatorów X i 99 znaków mnożenia! Ponieważ chcemy, by nasz algorytm był przydatny dla dowolnych potęg X, posłużymy się metodą iteracyjną, która polega na stopniowym dochodzeniu do wyniku przez wielokrotne powtarzanie tej samej sekwencji instrukcji,
W naszym przypadku, po zainicjowaniu zmiennej Wynik wartością 1, kolejno powtarzamy tę samą instrukcję:
Wynik:=Wynik*X;
Po każdym wykonania instrukcji, wartość zmiennej Wynik zostaje pomnożona przez X i zapamiętana jako nowa wartość zmiennej Wynik, zastępując wartość poprzednią. Z definicji operacji potęgowania wynika, że kolejne wartości przejściowe, przypisywane zmiennej Wynik, to kolejne potęgi liczby X. Chcąc podnieść X do potęgi N, musimy N-krotnie powtórzyć pokazaną instrukcję przypisania.
Chociaż opisana metoda jest ogólna, a wykonywana instrukcja przypisania jest bardzo prosta, to w przypadku dużych wartości wykładnika N program, napisany tak jak w przykładzie 6.2, nie byłby wygodny - musiałby zawierać bardzo wiele instrukcji. Na szczęście, w językach programowania można wykorzystywać tzw. instrukcje powtarzające. Instrukcje powtarzające Turbo Pascala omówione będą w rozdziale 8. Tam też zostanie przedstawiony bardziej zwięzły zapis pokazanych tutaj programów z iteracjami.
Przykład 6.2. Program do iteracyjnego obliczenia x3
program Ex6_2; {Iteracyjnie oblicza trzecią potęgę liczby czytanej z klawiatury.} uses Crt; var X,Wynik:Real; begin Clrscr; Write('Podaj liczbe: '); Readln(X); Wynik:=1.0; { Wynik=1.0} Wynik:=Wynik*X; { Wynik=1*X } Wynik:=Wynik*X; { Wynik=(1*X)*X } Wynik:=Wynik*X; { Wynik=(1*X*X)*X } Write('Wynik: ',Wynik:0:6); Readln; end.
|
W przykładzie 6.3 również posłużono się metodą iteracyjną, by znaleźć sumę i średnią wartość trzech kolejno wprowadzanych z klawiatury liczb. Do przechowania każdej kolejnej liczby służy ta sama zmienna X, a do przechowania sumy przejściowej zmienna Suma, którą inicjujemy wartością 0. W kolejnych krokach obliczeń powtarzana jest sekwencja trzech operacji:
Write('Podaj liczbe: ');
Readln(X);
Suma:=Suma+X;
Operacje te realizują kolejno następujące działania: wezwanie użytkownika do wprowadzenia liczby, odczyt tej liczby z klawiatury, powiększenie o tę liczbę aktualnej wartości zmiennej Suma, by uzyskać nową wartość tej zmiennej.
Po trzech krokach zmienna Suma przechowuje sumę trzech wprowadzonych z klawiatury liczb. Dzieląc tę sumę przez 3, dostajemy szukaną średnią arytmetyczną.
Przykład 6.3. Program iteracyjny obliczający sumę i średnią z trzech liczb
program Ex6_3; {Iteracyjnie sumuje 3 liczby czytane z klawiatury i liczy ich średnią.} uses Crt; var X,Suma,Srednia:Real; begin Clrscr; Suma:=0; Write('Podaj liczbe: '); Readln(X); Suma:=Suma+X; Write('Podaj liczbe: '); Readln(X); Suma:=Suma+X; Write('Podaj liczbe: '); Readln(X); Suma:=Suma+X; Srednia:=Suma/3; Write('Srednia z tych liczb to '); Write(Srednia:0:6); Readln; end.
|
Przykład 6.4 pokazuje obliczenie wartości funkcji silnia dla argumentu równego 6. Ponieważ argument jest niewielki, dla otrzymania wyniku można by zastosować pojedynczą instrukcję przypisania o postaci:
S:=1*2*3*4*5*6;
Z tych samych powodów, co poprzednio, tego typu podejście nie byłoby wygodne dla dużych argumentów silni, co więcej - nie pozwoliłoby uogólnić metody na dowolną wartość argumentu. Z tego powodu wybrano iteracyjną metodę obliczeń. W programie występuje pomocnicza zmienna I, równa początkowo 0, która w każdym kroku zwiększa się o 1, przyjmując kolejno wartości 1, 2, 3, 4, 5, 6. Przez te wartości, zgodnie z definicją silni, mnoży się kolejno wynik przejściowy, pamiętany w zmiennej S. Przed rozpoczęciem obliczeń S=1. Po sześciu powtórzeniach pary instrukcji, w zmiennej S znajdzie się szukany rezultat. W rozdziale 8 pokażemy, jak można zwięźle zapisać ten program, posługując się instrukcją powtarzającą.
Przykład 6.4. Iteracyjne obliczanie wartości silni liczby 6
program Ex6_4; {Oblicza iteracyjnie silnię liczby 6.} uses Crt; var S:Longint; I:Byte; begin Clrscr;
I:=0; {I=0} {Inicjalizacja} S:=1; {S=1}
I:=I+1; {I=0+1=1} {Krok 1} S:=S*I; {S=1*1=1}
I:=I+1; {I=1+1=2 {Krok 2} S:=S*I; {S=1*2=2}
I:=I+1; {I=2+1=3} {Krok 3} S:=S*I; {S=2*3=6}
I:=I+1; {I=3+1=4} {Krok 4} S:=S*I; {S:=6*4=24}
I:=I+1; {I=4+1=5} {Krok 5} S:=S*I; {S=24*5=120}
I:=I+1; {I=5+1=6} {Krok 6} S:=S*I; {S=120*6=720}
Write(' 6! = ',S); Readln; end. |
30