4. Operacje na danych (operatory i wyrażenia)
Na danych programu (zmiennych i literałach) możemy przeprowadzać
operacje. Są różne rodzaje tych operacji m.in.:
- arytmetyczne (np. dodawanie, odejmowanie, mnożenie, dzielenie,
dzielenie calkowitoliczbowe, uzyskanie reszty z dzielenia)
- przypisania (ustalenia wartości zmiennej)
- relacyjne (porównanie: czy coś jest równe, nierówne, większe,
mniejsze od czegoś innego)
- logiczne (obliczanie wartości logicznych)
- konkatenacja łańcuchów znakowych (łączenie napisów)
Operacje wyrażamy za pomocą operatorów języka.
Operator - to specjalny symbol języka służący do przeprowadzania
operacji na danych
Każdy język ma inny zestaw operatorów (symboli operacji). Dość
powszechne (takie same w większości języków) operatory pokazuje poniższa
tabela
* |
mnożenie |
/ |
dzielenie |
+ |
dodawanie |
- |
odejmowanie |
< |
mniejsze |
<= |
mniejsze lub równe |
>= |
większe lub rowne |
> |
większe |
= |
przypisanie |
O wartościach biorących udział w operacji (łączonych przez operator)
mówimy jako o argumentach operatora.
Np. operacja dodawania do zmiennej x wartości 1
Lewy argument
|
Operator
|
Prawy argument
|
x
|
+
|
1
|
Ze zmiennych, literałów i wywołań funkcji, za pomocą operatorów
i nawiasów, tworzymy wyrażenia.
W trakcie działania programu wyrażenia są "opracowywane" tzn.
określana jest ich wartość (każde wyrażenie ma jakąś wartość).
Załómy np., że zmienna x równa jest 100, zmienna a ma wartość
2
Wyrażenie
|
Wartość wyrażenia
|
x |
wartość zmiennej x czyli 100 |
1 |
wartość literału 1 czyli 1 |
x + 1 |
101 |
a * 2 + 3 |
7 |
Używajmy nawiasów dla określenia kolejności zastosowania operatorow
zawsze wtedy, gdy nie jesteśmy calkowicie pewni co do priorytetów operatorów
Zestaw operatorów charakteryzuje się priorytetami. Priorytety
mówią o tym w jakiej kolejności stosowane są operatory przy opracowywaniu
wyrażeń. Te operatory, które mają wyższy prirytet stosowane są najpiew.
Kolejność stosowania operatorow przy opracowaniu wyrażenia możemy zmienić
używając nawiasów.
Np. operator * ma wyższy priorytet niż operator + dlatego opracowanie
wyrażenia a*2 +3 daje w yniku 7 (przy a = 2). Jeśli chcemy zmienić
kolejność opracowania wyrażenia - użyjmy nawiasów:
a*(2+3)
To wyrażenie opracowywane jest w następujący sposób. Operator
* ma dwa argumenty lewym jest wyrażenie a (obliczana jest jego wartość;
rowna jest 2), prawym - wyrażenie 2+3 (obliczana jest jego wartość; równa
się 5). Wartość lewego argumentu mnożona jest teraz przez wartość prawego
argumentu. W wyniku otrzymamy 10.
Ważnym operatorem jest operator przypisania. Pozwala on
ustalać wartości zmiennych. Np.
cBazowa = 500; /* zmiennej
cBazowa nadajemy wartość 500 */
cProc = cBazowa; /* zmiennej
cProc nadajemy wartość zmiennej cBazowa (500) */
cProc = cBazowa - 100; /* zmiennej cProc wartość
zm. cBazowa pomniejszoną o 100 */
cProc = cProc + 200; /* cProc uzyskuje
nową wartość o 200 większą od poprzedniej jej wartości */
W tej chwili cProc = 600
Teraz tekst programu wyliczającego cenę komputera powinien być
prawie całkiem zrozumiały. Widzimy tam przecież właśnie zastosowanie
operatorów arytmetycznych (dodawanie i dzielenie) oraz przypisania. Pozostały
do wyjaśnienia tajemnicze konstrukcje typu:
say "Udział ceny procesora: " cProc/cKomp;
Mamy tu do czynienia nie tylko z dzieleniem (które jest chyba
zrozumiałe), ale również z konkatenacją (łączeniem) łańcuchów znakowych.
Nie przyzwyczajajmy się za bardzo do operatorow konkatenacji
REXXa, bowiem w Javie konkatenacja łańcuchów znakowych jest znacznie
uboższa i wygląda nieco inaczej, choć są pewne podobieństwa. W szczególności,
mamy tam operator +, który dziala tak samo jak operator || w REXXie, a także
- mimo, że Java jest językiem ze ścisłą kontrolą typów, możemy zmienne
typu łańcuchowego (napisowego) łączyć ze zmiennymi dowolnych innych typów
i otrzymywać w rezultacie łańcuchy znakowe.
W REXXie konkatenacja łańcuchów znakowych może być realizowana na trzy sposoby:
- za pomocą operatora || (do lewego argumentu dołączany jest prawy,
bez spacji między nimi)
- za pomocą spacji pomiędzy dowolnymi wyrażeniami (do lewego argumentu
dołaczana jest spacja, a następnie prawy argument)
- za pomocą "przytulenia" zmiennej do literału łańcuchowego (do
literału łańcuchowego dołączana jest zawartość zmiennej traktowana jako
napis)
przy czym wszystkie dane w REXXie (w tym liczby) traktowane są
przy konkatenacji jak łańcuchy znakowe (napisy).
Zob. dodatkowe wyjaśnienia.
Przykładowo, jeżeli zmienne liczbowe a i b mają wartości 100
i 50, a zmienna łańcuchowa napis zawiera tekst "ala" to:
Wyrażenie w REXXie
|
Wynik
|
Jak to można zapisać w Javie
|
"kot" a/b
|
kot 2
|
"kot" + " " + a/b
|
napis||a
|
ala100
|
napis + a
|
a||b
|
10050
|
"" + a + b
|
"kot"napis
|
kotala
|
"kot" + napis
|
Wracając do wyjaśnienia działania instrukcji:
say "Udział ceny procesora: " cProc/cKomp;
możemy teraz stwierdzić, że instrukcja say ma postać:
say wyrażenie;
gdzie wyrażenie jest dowolnym wyrażeniem, które zostaje
opracowane a jego wynik (traktowany jako napis) wyprowadzony na konsolę.
W naszym przykładzie do napisu w cudzysłowie dołączana jest spacja
a po niej napis reprezentujący wynik dzielenia wartości zmiennej cProc
przez wartość zmiennej cKomp.
Operatory porównania (relacyjne) mają szczególną właściwość.
Wynikiem ich zastosowania jest jedna z dwóch wartości prawda lub
fałsz. W różnych językach stosowane są różne konwencje na
oznaczenie tych wartości. Czasami (jak w Javie) są to wartości specjalnego
typu, oznaczane słowami kluczowymi true i false. Czasami
jak w REXXie są to wartości 1 (prawda) i 0 (falsz).
Zastosowanie operatorów relacyjnych możemy kojarzyć z odpowiedzią
na pytanie: czy prawdziwy jest warunek przez nie opisywany.
Np.
x > 5
pytanie: czy wartość zmiennej x jest większa od 5
odpowiedź: tak/nie, podawana jako wynik 1/0 lub
true/false
x <= y
pytanie: czy wartość zmiennej x jest mniejsza lub równa wartości
zmiennej y
odpowiedź: tak/nie, podawana jako wynik 1/0 lub
true/false
Szczególne operatory relacyjne: równości i nierówności
sprawiają trochę kłopotu. Naturalnym bowiem sposobem zapisu tych operatorów
jest użycie znaku '='. Tak robi to REXX.
Piszemy więc a = b, by sprawdzić, czy wartość zmiennej a równa
się wartości zmiennej b? Ale zaraz, zaraz: przecież to jest również
przypisanie! Jak je rozróżnić?
W REXXie zależy to od kontekstu użycia.
Jeżeli napiszemy w nowym wierszu, lub po średniku:
a = b;
to będzie to potraktowane jako instrukcja przypisania, a nie
jako wyrażenie, które ma wynik.
Jeżeli natomiast tego samego zapisu użyjemy w miejscu, gdzie
oczekiwana jest wartość jakiegoś wyrażenia np.
if (a = b)
say a = b
to znak równości będzie potraktowany jako operator równości (nie
przypisania), i wyrażenie a = b da wynik 1 lub 0 (odpowiedż na pytanie
czy a jest równe b - prawda to czy fałsz?).
W innych językach (m.in. C, C++, Javie) wyraźnie rozróżnia się
operatory przypisania i równości. Ten ostatni ma formę ==
(dwa znaki równości). Dzięki temu semantyka języka jest (w tym kontekście)
jednolita: przypisanie również jest wyrażeniem i ma wartość (prawej
strony operatora przypisania).
Niestety, ma to również swoje złe strony (zobacz o efektach ubocznych).
Operator równości
|
W REXXie
|
W Javie
|
=
|
==
|
Przykład:
a = b
Znaczenie:
czy a równa się b?
wynik: 1 (tak), 0 (nie)
|
Przykład:
a == b
Znaczenie:
czy a równa się b?
wynik: true (tak), false (nie)
|
Operator nierówności uzyskamy stawiając znak negacji przed
znakiem '='. W REXXie znakiem tym będzie \ (backslash), w C, C++, Javie
! (wykrzyknik).
Przykład:
REXX: a \= b (wynik: 1, jeśli a nie jest równe b, 0 w przeciwnym
przypadku)
Java: a != b (wynik: true, jeśli a nie jest równe
b, false w przeciwnym przypadku)
Znak negacji jest też samodzielnym operatorem logicznym, oznaczającym
logiczne zaprzeczenie.
Operatory logiczne służą do konstruowania wyrażeń logicznych
za pomocą łączników : i. lub.
W REXXie operator koniunkcji logicznej oznaczany jest przez &, zaś alternatywa
- przez | ( w C, C++, Javie stosowane są tu operatory && i || - podwójne
& i | )
Więcej na ich temat (a także innych operatorów) przy okazji omawiania
wyrażeń i operatorów Javy.
|