« poprzedni punkt 

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 "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.


« poprzedni punkt