Tajemnice ATARI

PIERWSZE KROKI

    Zgodnie z zapowiedzią zastanowimy się dzisiaj wspólnie nad pętlami. Życie podpowiada nam, że jest to sprytna konstrukcja, która powoduje wykonywanie jakiejś sekwencji rozkazów "w kółko". Najprostszym przykładem może być pętla nieskończona polegająca na bezwarunkowym skoku w miejsce poprzedzające komendę skoku.

Przykłady:
10 GOTO 10


10 LIST
20 GOTO 10
   Taką konstrukcję już poznaliśmy w trzecim odcinku cyklu (TA 5). Wyżej opisana pętla bez żadnych modyfikacji jest jednak używana bardzo rzadko. Niewiele jest sytuacji, w których zależy nam na wykonywaniu jakiejś sekwencji komend bez żadnej możliwości przerwania tego procesu (nie używając klawisza BREAK lub RESET, co jest ulubionym zajęciem początkujących programistów). Zazwyczaj tworzy się więc pętle z różnorakimi warunkami końca lub wyjścia. Taką sytuację też już mieliśmy we wspomnianym trzecim odcinku cyklu. Użyta tam została komenda IF wyrażenie THEN działanie do sprawdzenia odpowiedniego warunku i ewentualnego opuszczenia (kontynuowania) pętli. Sama komenda IF została wtedy szczegółowo opisana. Aby dopełnić nasze wiadomości na temat opuszczania pętli warunkowej należy rozróżnić jej dwa typy:

1. Pętla z badaniem warunku końca na końcu pętli.

2. Pętla z badaniem warunku końca na początku pętli.

   Z równym powodzeniem stosowane są obydwa, lecz już w fazie projektowania programu warto zastanowić się, który nadaje się lepiej do osiągnięcia określonego celu. Jeżeli chcemy na przykład zapętlić cały program, to pytanie "Czy mam powtórzyć program" i odpowiednią reakcję powinno się oczywiście umieścić na jego końcu (końcu pętli głównej). Jeżeli istnieje podejrzenie, że nawet jednokrotne wykonanie sekwencji komend może spowodować błędne działanie lub frustrację u użytkownika programu, to warunek końca należy rozstrzygnąć na początku pętli.

   Aby się nieco oswoić z różnorakimi pętelkami spróbujemy obliczyć sumę liczb od 1 do 123.
10 LICZBA=1:SUMA=0
20 SUMA=SUMA+LICZBA
30 LICZBA=LICZBA+1
40 IF LICZBA<>123+1 THEN 20
50 ? SUMA:END
   Sam programik jest bardzo prosty, choć całkiem "zielonym" konstrukcja SUMA=SUMA+LICZBA może wydawać się dziwna. Powoduje ona po prostu dodanie do poprzedniej wartości SUMY kolejnej LICZBY (zwiększanej w wierszu 30). Wiersz 10 jest koniecznym ustaleniem wartości początkowych SUMY i LICZBY.

   Przyjrzyjmy się baczniej wierszowi 40. Jest to właśnie badanie warunku końcowego pętli. Polega na sprawdzeniu, czy LICZBA przekroczyła już 123 (stąd 123+1) i jeżeli nie, to należy kontynuować obliczenia. Sprawdźmy teraz, jak będzie się zachowywał program dla dowolnej wartości początkowej i końcowej LICZBY. Wszystko będzie w porządku dla wartości początkowej mniejszej bądź równej wartości końcowej. Gdyby tak jednak w wierszu 10 napisać LICZBA=8, a po słowie IF w wierszu 40 napisać LICZBA<>5+1? Oczekiwalibyśmy obliczenia sumy liczb od 8 do 5. Z punktu widzenia logiki jest to bez sensu, lecz przy pisaniu programów często może się zdarzyć. Co więc zrobi nasz program? Napiszmy RUN i poczekajmy chwilkę. Nic? No to jeszcze chwilkę. Niestety nie doczekamy się niczego. Program się po prostu ZAWIESIŁ.

   Złe dobranie parametrów spowodowało, że pętla nagle stała się bez końca. Pomóżmy sobie i komputerowi naciskając BREAK. Możemy nawet sprawdzić obliczoną wartość SUMY pisząc po prostu ? SUMA i naciskając RETURN. Naszym oczom ukaże się dziwna liczba niezbyt przystająca do naszego wyobrażenia o wyniku. Jaki wynik pragnęlibyśmy osiągnąć? Zakładając, że istnieje tylko suma liczb liczona od mniejszej do większej (lekka herezja matematyczna) powinno to być 0 (zero). Zastanówmy się dlaczego program nie działał prawidłowo. Otóż nigdy zwiększając jakąś liczbę nie możemy otrzymać liczby mniejszej. Zatem nasz warunek końca jest do wyrzucenia. A gdyby tak zamiast sprawdzania czy LICZBA osiągnęła wartość o jeden większą od 5 zbadać, czy jest od niej większa? Napiszmy
40 IF LICZBA <=5 THEN 20
i wykonajmy program. Tym razem będziemy bliżej sukcesu, bowiem jakiś wynik uzyskamy. Niestety i tym razem będzie on daleki od oczekiwań. Zamiast zera ujrzymy na ekranie ósemkę. Można by oczywiście dodać przed początkiem pętli dodatkowy warunek sprawdzający poprawność wprowadzonych danych, lecz prościej (albo poprawniej) jest przenieść badanie warunku końca na początek pętli
10 LICZBA=8:SUMA=0
15 IF LICZBA>=5 THEN 50
20 SUMA=SUMA+LICZBA
30 LICZBA=LICZBA+1
40 GOTO 15
50 ? SUMA: END
zmieniając nieco warunek i wymuszając wierszem 40 bezwarunkowy skok na początek pętli. Teraz pełny sukces jest gwarantowany.

   Należałoby oczywiście wspomnieć o możliwości badania warunku końca pętli w jej środku, lecz jest to sposób nieelegancki i w znaczny sposób zakłóca przejrzystość programu.

   Opisane pętle są w pewien sposób "sztuczne", to znaczy budowane z pomocą odrębnych komend basicu służących również do innych celów. Jedyną komendą czysto basicową służącą do budowania pętli jest konstrukcja z FOR.

   FOR licznik=wartość początkowa TO wartość końcowa STEP krok ...(ciąg komend)... NEXT licznik

W skrócie FOR zapisujemy F. a NEXT N.

   Opisana wyżej konstrukcja oznacza polecenie powtarzania ciągu komend, dopóki licznik nie osiągnie wartości końcowej, z zastrzeżeniem, że zmieniany jest o krok podany po słowie STEP. Krok może być ujemny, a gdy ma wynosić 1 można pominąć słówko STEP i jego wartość.

   Nasz programik zapisany przy użyciu tej pętli wyglądałby następująco:
10 SUMA=0
20 FOR LICZBA=8 TO 5
30 SUMA=SUMA+LICZBA
40 NEXT LICZBA
50 ? SUMA: END
   Jego wygląd może sugerować, że warunek końca pętli (8<=5) będzie sprawdzony na początku.

   Niestety nic bardziej mylnego. W ATARI BASIC warunek końca pętli FOR jest sprawdzany na jej końcu (sic!). Może to czasem prowadzić do tragicznych pomyłek, gdyż pętla ta zawsze wykonuje się przynajmniej raz. Spróbujcie sami. Jak w powyższym przykładzie użycie najprostszej i przejrzystej konstrukcji FOR do organizacji pętli nie musi być najefektywniejsze.

   Jeszcze jedna ważna uwaga na temat pętli FOR..NEXT. Należy stanowczo unikać zmian wartości licznika w jej wnętrzu.

   Zazwyczaj chcemy, by nasze programy wykonywały się szybko. Należy unikać umieszczania wewnątrz pętli zbędnych komend, badania zbytnio złożonych warunków, zwłaszcza w pętlach wykonujących się dużo razy. Przy tysiąckrotnym wykonaniu dodanie nawet "szybkiej" komendy może znacznie zwolnić wykonanie całości.

   W piątym numerze Tajemnic Atari do cyklu "Pierwsze kroki" zakradł się błąd. Jest to, niestety, pomyłka bardzo istotna. Nie tyle z powodu wagi poruszanego problemu, choć prezentowany programik nie zachowywał się poprawnie, lecz z uwagi na nieodpowiedzialność autora. Podszedłem do opracowania przykładu zbyt machinalnie i nie sprawdziłem go. Polegałem tylko na swojej głowie. Okazało się to zgubne w skutkach. Przyznaję się do błędu bez bicia, gdyż z tej całej przygody płynie ważna nauka. Do programowania nie wystarczy sama wiedza i doświadczenie. Nawet najlepszy program nie przetestowany jest gorszy od każdego działającego poprawnie.

   Zobaczmy wreszcie na czym polegał błąd. Wiersz 50 podany na końcu artykułu powinien wyglądać następująco:
50 IF ODPOW$<>"N" AND ODPOW$<>"n" THEN 30
   Jeszcze raz przepraszam.

Mirosław Liminowicz



Powrót na start | Powrót do spisu treści | Powrót na stronę główną

Pixel 2001