Rozdział 9


FUNKCJE

 

Podsumowanie

 

Rozważmy maszynę do robienia kiełbasek. Wkłada się z jednej strony kawał mięsa, przekręca dźwignię, a z drugiej strony wychodzi kiełbaska. Mięso wieprzowe da kiełbasę wieprzową, mięso rybne da kiełbasę rybną, a wołowina da kiełbasę wołową.

Funkcje są praktycznie nierozróżnialne od maszyny do kiełbasek, lecz jest pewna różnica: działają one na liczbach i łańcuchach, a nie na mięsie. Dostarczasz jedna wartość (zwaną argumentem), mielisz ją wykonując na niej jakieś obliczenia, a na końcu otrzymujesz inną wartość, wynik.

 

Wprowadzanie mięsa →

     Maszyna do kiełbasek     

→ Wyjście kiełbaski

Wprowadzanie argumentu →

Funkcja

→ Wyjście wyniku

 

Różne argumenty dają różne wyniki, a jeśli argument jest zupełnie nieodpowiedni, to funkcja zatrzyma się i da raport błędów.

Skoro możesz posiadać różne maszyny do robienia różnych produktów — jedną do kiełbasek, drugą do ścierek, a trzecią do paluszków rybnych itd., różne funkcje będą wykonywały różne obliczenia. Każda będzie posiadała swoją własną wartość w celu odróżnienia jej od innych.

Funkcję stosujesz w wyrażeniach przez wpisanie jej nazwy, za którą występuje argument, a kiedy to wyrażenie będzie obliczane, zostanie wyznaczony wynik funkcji.

Dla przykładu mamy funkcję o nazwie LEN, która wylicza długość łańcucha. Jej argumentem jest łańcuch, którego długość chcesz znaleźć, a wynikiem ta długość, zatem jeśli wpiszesz

 

PRINT LEN "Sinclair"

 

to komputer wypisze odpowiedź 8, czyli liczbę znaków w 'Sinclair'. (Aby otrzymać LEN, jak przy większości nazw funkcji, musisz użyć trybu rozszerzonego: naciśnij jednocześnie CAPS SHIFT i SYMBOL SHIFT, aby zmienić kursor z  L  na  E , a następnie naciśnij klawisz K.)

Jeśli w jednym wyrażeniu wymieszasz funkcje i operacje, to funkcje będą wyliczane przed operacjami. Jednakże możesz obejść tę regułę, stosując nawiasy. Na przykład, oto dwa wyrażenia, które różnią się jedynie nawiasami, a mimo to obliczenia są wykonywane w całkowicie innej kolejności w każdym z nich (chociaż, co się czasami zdarza, wynik końcowy jest taki sam).

 

LEN "Fred"+ LEN "Bloggs"

LEN ("Fred"+"Bloggs")

4+LEN "Bloggs"

LEN ("FredBloggs")

4+6

LEN "FredBloggs"

10

10

 

Oto kilka dalszych funkcji.
 

STR$ zamienia liczby na łańcuchy: jej argumentem jest pewna liczba, a wynikiem łańcuch, który pojawiłby się na ekranie, gdyby tę liczbę wyświetlić za pomocą rozkazu PRINT. Zwróć uwagę na zakończenie nazwy tej funkcji znakiem $, co pokazuje, że wynik jest łańcuchem. Na przykład, mógłbyś wpisać polecenie

 

LET a$=STR$ 1e2

 

które dałoby dokładnie taki sam efekt jak wpisanie

 

LET a$="100"

 

Albo mógłbyś wpisać

 

PRINT LEN STR$ 100.0000

 

i otrzymałbyś odpowiedź 3, ponieważ STR 100.0000="100".

 

VAL jest jakby odwrotnością STR$: zamienia ona łańcuchy w liczby. Na przykład

 

VAL "3.5"=3.5

 

W pewnym sensie VAL jest odwrotnością STR$, ponieważ jeśli weźmiesz dowolną liczbę i zastosujesz do niej funkcję STR$, a następnie VAL do wyniku, to otrzymasz z powrotem początkową liczbę. Jednakże, jeśli weźmiesz łańcuch, zastosujesz do niego VAL, a następnie STR$ do wyniku, to nie zawsze otrzymasz z powrotem oryginalny łańcuch.

VAL jest niesamowicie potężną funkcją, ponieważ łańcuch będący jej argumentem nie jest ograniczony do wyglądania jak goła liczba — może to być dowolne wyrażenie liczbowe. W ten sposób przykładowo

 

VAL "2*3"=6

 

lub nawet

 

VAL("2"+"*3")=6

 

Pracują tu dwa procesy. W pierwszym argument VAL zostaje przeliczony jako łańcuch: wyrażenie łańcuchowe "2"+"*3" jest przetwarzane i daje w wyniku łańcuch "2*3". Następnie z łańcucha tego zostają usunięte ograniczające nawiasy, a to co zostaje jest obliczane jako liczba: zatem 2*3 jest obliczane dając w wyniku 6.

Może to być dosyć pogmatwane, jeśli przestaniesz się posługiwać rozumem; na przykład

 

PRINT VAL "VAL""VAL""""2""""""

 

(Pamiętaj, że wewnątrz łańcucha cudzysłów musi być wpisany dwukrotnie. Jeśli wejdziesz w zagnieżdżenia łańcuchów, to odkryjesz, że cudzysłów musi być powtórzony czterokrotnie, a nawet ośmiokrotnie.)

Istnieje jeszcze jedna funkcja, raczej podobna do VAL, chociaż prawdopodobnie mniej przydatna. Nazywa się VAL$. Jej argumentem wciąż jest łańcuch, lecz wynikiem też jest łańcuch. Aby zrozumieć jej działanie, przypomnij sobie sposób działania VAL w dwóch krokach: najpierw jej argument zostaje przetworzony jako łańcuch, następnie usuwane są cudzysłowy, a to co zostanie jest przetwarzane jako liczba. Z VAL$ pierwszy krok jest taki sam, lecz po usunięciu cudzysłowów łańcucha w drugim kroku, to co pozostało jest przetwarzane jak kolejny łańcuch. Stąd

 

VAL$ """Misiek Bubu""" = "Misiek Bubu"

 

(Zauważ, jak znów rozmnożyły się cudzysłowy.) Wykonaj

 

LET a$="99"

 

i wydrukuj na ekranie każde z następujących wyrażeń: VAL a$, VAL "a$", VAL """a$""", VAL$ a$, VAL$ "a$" i VAL$ """a$""". Niektóre z nich będą działać, a inne nie; postaraj się wyjaśnić wszystkie wyniki. (Nie zgrzej się zbytnio.)

 

SGN jest funkcją znaku (czasami zwaną z łaciny signum znak). To pierwsza oglądana przez ciebie funkcja, która nie ma nic wspólnego z łańcuchami, ponieważ zarówno jej argument jak i wynik są liczbami. Wynik wynosi +1, jeśli argument jest dodatni (większy od zera), 0, jeśli  argument jest równy zero i -1, jeśli argument jest ujemny (mniejszy od zera).

 

ABS to kolejna funkcja, której argument i wynik są liczbami. Zamienia ona argument na liczbę dodatnią (lub zero), co staje się jej wynikiem, przez opuszczenie znaku, zatem przykładowo:

 

ABS -3.2 = ABS 3.2 = 3.2

 

INT oblicza część całkowitą liczby, również ujemną. Funkcja ta zamienia liczbę ułamkową na liczbę całkowitą przez odrzucenie jej części ułamkowej, zatem przykładowo

 

INT 3.9 = 3

 

Uważaj, gdy stosujesz tę funkcję do liczb ujemnych, ponieważ zawsze zaokrągla ona w dół: stąd przykładowo

 

INT -3.9 = -4

 

SQR oblicza pierwiastek kwadratowy liczby — wynik, który pomnożony przez siebie daje argument. Na przykład

 

SQR 4 = 2, ponieważ 2*2=4

SQR 0.25 = 0.5, ponieważ 0.5*0.5=0.25

SQR 2 = 1.4142136 (w przybliżeniu), ponieważ 1.4142136*1.4142136=2.0000001

 

Jeśli pomnożysz przez siebie dowolną liczbę (nawet ujemną), to wynik jest zawsze dodatni (lub równy zero dla zera). Oznacza to, iż liczby ujemne nie posiadają pierwiastków (w zbiorze liczb rzeczywistych, oczywiście — istnieją tzw. pierwiastki zespolone, ale to inna bajka), zatem jeśli zastosujesz SQR do ujemnego argumentu, otrzymasz raport błędu A Invalid Argument (A Nieprawidłowy Argument).

 

Możesz również samemu definiować funkcje. Dozwolona nazwa dla takiej funkcji składa się z FN i litery (jeśli wynik to liczba) lub FN litera i znak $ (jeśli wynik jest łańcuchem). Funkcje te są bardziej restrykcyjne na temat nawiasów: argument musi być umieszczony w nawiasach.

Funkcję definiujesz, umieszczając gdzieś w programie polecenie DEF. Na przykład, oto definicja funkcji FN s, której wynikiem jest kwadrat argumentu:

 

10 DEF FN s(x)=x*x: REM kwadrat x

 

DEF uzyskuje się w trybie rozszerzonym, używając SYMBOL SHIFT i 1. Gdy wpiszesz to, komputer da ci automatycznie FN, ponieważ w poleceniu DEF za słowem DEF zawsze występuje bezpośrednio FN. Na koniec s zamyka nazwę funkcji FN s.

x w nawiasach jest nazwą, za pomocą której chcesz się odwoływać do argumentu funkcji. Do tego zadania możesz użyć dowolnej jednoliterowej nazwy (lub w przypadku argumentu łańcuchowego — nazwy jednoliterowej z $).

Po znaku = następuje właściwa definicja funkcji. Może to być dowolne wyrażenie i może ono odwoływać się również do argumentu, wykorzystując nadaną mu przez ciebie nazwę (w tym przypadku jest to x) tak, jakby była to zwykła zmienna.

Gdy wprowadzisz ten wiersz, możesz wywołać zdefiniowaną funkcję  w taki sam sposób, jak funkcje własne komputera, wpisując jej nazwę FN s, a następnie argument. Pamiętaj, że dla funkcji zdefiniowanych przez ciebie argument musi być umieszczony w nawiasach. Wypróbuj to kilka razy:

 

PRINT FN s(2)

PRINT FN s(3+4)

PRINT 1+INT FN s(LEN "kurczaki"/2+3)

 

Po umieszczeniu w programie odpowiedniego polecenia DEF, możesz używać własnych funkcji w wyrażeniach tak samo swobodnie, jak funkcji komputera.

 

Uwaga: w niektórych dialektach języka BASIC należy w nawiasach umieszczać nawet argumenty funkcji własnych komputera. Tak nie jest w ZX Spectrum BASIC.

INT zawsze zaokrągla w dół. Aby zaokrąglić do najbliższej liczby całkowitej, dodaj najpierw .5 — mógłbyś napisać własną funkcję, która to robi:

 

20 DEF FN r(x)=INT (x+0.5): REM daje x zaokraglone do najblizszej liczby calkowitej.

 

Wtedy otrzymywałbyś przykładowo:

 

FN r(2.9) = 3     FN r(2.4) = 2

FN r(-2.9) = -3   FN r(-2.4) = -2

 

Porównaj te wyniki z wynikami, gdy zamiast FN r zastosujesz samo INT.

 

Wpisz następujący program:

 

10 LET x=0: LET y=0: LET a=10
20 DEF FN p(x,y)=a+x*y
30 DEF FN q()=a+x*y
40 PRINT FN p(2,3),FN q()

 

W programie tym występuje wiele subtelności.

Po pierwsze, funkcja nie jest ograniczona do jednego argumentu: może posiadać ich więcej lub nawet żadnego — lecz wciąż muszą pozostać nawiasy.

Po drugie, nie ma znaczenia, gdzie w programie umieścisz polecenia DEF. Gdy komputer wykona wiersz 10, po prostu przeskoczy wiersze 20 i 30, aby przejść do wiersza 40. Jednakże muszą one być gdzieś w programie. Nie można umieścić ich w rozkazie bezpośrednim (bez numeru wiersza).

Po trzecie, x i y są zarówno nazwami zmiennych w programie jako całości oraz nazwami argumentów funkcji FN p. Funkcja ta tymczasowo zapomina o zmiennych zwanych x i y, lecz nie mając na liście argumentów a, wciąż pamięta o zmiennej a. Stąd, gdy FN p(2,3) jest obliczane, a posiada wartość 10, ponieważ jest to zmienna, x ma wartość 2, ponieważ jest to pierwszy argument, a y ma wartość 3, ponieważ jest drugim argumentem. Wynikiem jest więc 10+2*3=16. Z drugiej strony, gdy FN q() jest obliczane, nie ma żadnych argumentów, zatem a, x i y wciąż odnoszą się do zmiennych i posiadają wartość odpowiednio 10, 0 i 0. Wynikiem w tym przypadku jest 10+0*0=10.

Teraz zmień wiersz 20 na

 

20 DEF FN p(x,y)=FN q()

 

Tym razem FN p(2,3) da wynik 10, ponieważ FN q wciąż wraca do zmiennych x i y, a nie do argumentów funkcji FN p.

 

Niektóre języki BASIC (ale nie ZX Spectrum BASIC) posiadają funkcje o nazwach LEFT$, RIGHT$, MID$ i TL$.

LEFT$(a$,n) daje podłańcuch a$ składający się z n pierwszych znaków.

RIGHT$(a$,n) daje podłańcuch a$ składający się z n ostatnich znaków.

MID$(a$,n1,n2) daje podłańcuch a$ składający się z n2 znaków poczynając od pozycji n1.

TL$(a$) daje podłańcuch a$ zawierający wszystkie znaki z wyjątkiem pierwszego.

Możesz napisać kilka funkcji użytkownika, które będą wykonywały to samo: np.

 

10 DEF FN t$(a$)=a$(2 TO ): REM TL$

20 DEF FN l$(a$,n)=a$( TO n): REM LEFT$

 

Sprawdź, czy funkcje te dobrze działają z łańcuchami o długości 0 lub 1.

Zauważ, że nasza funkcja FN l$ ma dwa argumenty, jeden łańcuchowy a drugi liczbowy. Funkcja może posiadać do 26 argumentów liczbowych (dlaczego akurat 26?), a w tym samym czasie również do 26 argumentów łańcuchowych.

 

Ćwiczenie

Użyj funkcji FN s(x)=x*x to przetestowania SQR: powinieneś odkryć, że

 

FN s(SQR x)=x

 

jeśli za x podstawisz dowolną liczbę dodatnią, i

 

SQR FN s(x)=ABS x

 

bez względu na znak x (dlaczego ABS?).

 

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2018 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe