Algorytmy numeryczne i pliki wsadowe |
Wpisany przez Tomasz Stasiak | |
niedziela, 23 października 2011 21:56 | |
Zacznijmy od początku - czym są pliki wsadowe, a czym algorytmy numeryczne? Pliki wsadowe są wykorzystywane w różnych systemach operacyjnych (np. Linux, Windows, DOS, etc.) do wykonywania prostych zadań związanych głównie z zarządzaniem komputerem dzięki temu możemy np. zautomatyzować pewne zadania; w czasach DOS-a pliki wsadowe były wykorzystywane do tworzenia ustawień przy starcie systemu. Jeśli chodzi natomiast o algorytmy numeryczne, to mówiąc najprościej są to wszystkie algorytmy, które wykonują operacje na liczbach (żeby nie było wątpliwości: chodzi o to, że to ma być główny cel algorytmu, a nie np. operacja wykonywana przy przetwarzaniu tekstu :)). Ten tekst (a w zasadzie cykl tekstów) będzie dotyczył plików wsadowych w systemie Windows (acz w DOS-ie powinno działać także); mają one rozszerzenie *.cmd lub *.bat. Dlaczego ten OS? Bo pracuję aktualnie na takim, nie innym systemie.
Ale do rzeczy: jak nie trudno wywnioskować ze wstępu (który może nie był zbyt pasjonujący, ale potrzebny), pliki wsadowe raczej nie są tym, o czym pomyślimy, kiedy będziemy mieli jako zadanie napisanie programu/skryptu, który ma coś liczyć. Jest ku temu kilka powodów: głównie - treść plików wsadowych to w większości wywołania innych programów, brak normalnej pętli for, czy dziwnie działająca instrukcja if. Chociaż i tak największym mankamentem jest sposób traktowania zmiennych - domyślnie wszystkie zmienne (środowiskowe BTW) są traktowane jako tekst, co trochę utrudnia zadanie; nie można użyć tego typu konstrukcji: set var=1 set var=%var% + 1 echo %var% Ponieważ da ona następujący wynik: %var% = 1 + 1 (zostało to potraktowane jako tekst, a nie jako liczba, jak można by oczekiwać). Okazuje się, że mamy tu do czynienia z typowaniem dynamicznym słabym i na dodatek, aby interpreter (np. cmd.exe lub command.com) traktował te zmienne jako liczby musimy użyć set z przełącznikiem /A. Rozpatrzmy jeszcze raz nasz przykład: set /A var=1 set /A var=%var% + 1 echo %var% Teraz wynikiem działanie będzie %var% = 2, czyli to, co chcieliśmy :). Wracając do wspomnianej pętli for - w normalnych językach programowania pętla działa w następujący sposób: sprawdzamy warunek i dopóki nie jest on spełniony wykonujemy zawartość tejże pętli. Tutaj natomiast pętla wykonuje się tylko dla elementów podanych jako argument. Tak więc, aby wykonać pętlę z n obrotami w tradycyjny sposób musielibyśmy za każdym razem wpisywać tam właśnie te n elementów. A to chyba odpada? :) Jak więc to zrobić? Jeśli ktoś z was programował w asemblerze, to wie, że pętlę można zorganizować na 2 sposoby:
W plikach wsadowych nie mamy co prawda niczego takiego, ale na pomoc mogą nam przyjść odpowiedniki - zamiast jmp mamy instrukcję goto, a zamiast test/cmp możemy użyć if'a. Tutaj uwaga: if w plikach wsadowych ma kilka dziwnych zachowań, na które trzeba uważać:
To już chyba wszystko, o czym warto wspomnieć, jeśli o czymś zapomniałem - wyjdzie w praniu :). Mając te wszystkie informacje możemy się zabrać za pisanie, na rozgrzewkę niech będzie skrypt wypisujący wszystkie liczby z zakresu od 1 do n (włącznie), gdzie n jest argumentem podanym z linii poleceń. Zaczynamy, oczywiście, od znanej (mam nadzieję) wszystkim linijki: @echo off Która ma wyłączyć wyświetlanie aktualnie parsowanej linijki; następnie można stworzyć i ustalić wartość początkową zmiennych (jeszcze jedna uwaga: wszystkie są traktowane jako globalne i pozostają nawet po wykonaniu skryptu - do zamknięcia konsoli), wyświetlić jakieś informacje o tym, kto jest autorem, czy sprawdzić, czy użyszkodnik na pewno podał argument (bo skąd mamy wiedzieć, do ilu liczyć?): rem iterator w pętli set /a var = 1 echo Program wypisujacy kolejne liczby calkowite od 1 do n echo . echo Copyright 2011 Tomasz Stasiak echo . Komenda REM oznacza komentarz, została wpisana dla wyjaśnienia, co się dzieje; natomiast echo . jest umieszczone, aby wyświetlić "pustą linię" - jeśli po echo nie będzie żadnego, niebiałego znaku (czyli czegoś oprócz spacji, tabulatora, znaku nowej linii, etc.), to nie zostanie wyświetlone nic; tu dzięki temu zyskujemy odstęp między pierwszą, trzecią i pozostałymi wyświetlanymi liniami. %1 jest oznaczeniem parametru przesłanego do pliku - %0 to zawsze nazwa pliku, kolejne numery mają argumenty wpisywane w konsoli. Program się wykona przy takim wywołaniu (zakładając, że nazwa pliku to liczby_od_1_do_n.bat): C:\>liczby_od_1_do_n.bat 10 Natomiast po wywołaniu w ten sposób: C:\>liczby_od_1_do_n.bat Skoczy do etykiety null_arg, która ma na celu obsłużenie wywołania bez argumentu: rem obsługa w wypadku braku argumentu :null_arg echo Nie podales argumentu! echo . echo Uzycie: %0 n echo Gdzie: echo n oznacza ilość liczb do wypisania goto end end jest etykietą dodaną na końcu pliku, służy do skoku, aby można było pominąć pewne sekcje, które nie mają się wykonać, widać tu jak bardzo przydatny okazuje się fakt, że %0 zawiera nazwę pliku. No dobrze, jesteśmy już przygotowani - wiemy, że użytkownik podał argument, a potrzebne nam zmienne istnieją, należy tylko utworzyć pętlę, w której wypiszemy kolejne liczby. W jaki sposób? Otóż, jak wspominałem, istnieje możliwość utworzenia etykiety i skakania do niej, dopóki argument nie jest spełniony: rem etykieta w pętli - stary, "dobry" sposób znany z asemblera :loop rem wyświetlenie liczby echo %var% rem sprawdzenie, czy zmienna nie osiągnęła wymaganego numeru if "%var%" == "%1" goto end rem inkrementacja zmiennej o 1 set /A var += 1 rem powrót do początku pętli goto loop Wyjaśnienie krok po kroku, co się dzieje:
Zbierając to wszystko "do kupy" otrzymujemy: @echo off rem Zmienne: rem iterator w pętli set /a var = 1 echo Program wypisujacy kolejne liczby calkowite od 1 do n echo . echo Copyright 2011 Tomasz Stasiak echo . rem sprawdzenie, czy wszystkie argumenty są ok if "%1" == "" goto null_arg rem pusty argument rem etykieta w pętli - stary, "dobry" sposób znany z asemblera :loop rem wyświetlenie liczby echo %var% rem sprawdzenie, czy zmienna nie osiągnęła wymaganego numeru if "%var%" == "%1" goto end rem inkrementacja zmiennej o 1 set /A var += 1 rem powrót do początku pętli goto loop rem obsługa w wypadku braku argumentu :null_arg echo Nie podales argumentu! echo . echo Uzycie: %0 n echo Gdzie: echo n oznacza ilość liczb do wypisania goto end :end Jak widać, na końcu pliku pojawia się wspomniana wcześniej etykieta end, za którą nic więcej nie ma. Plik do pobrania: liczby_od_1_do_n.bat (należy zmienić rozszerzenie na .bat). Niestety, nie ma kolorowania składni, bo Joomla nie daje takiej możliwości :( Dodatkowo, z przykrością (no, w sumie bardziej zależy dla kogo :)) informuję, że tym wpisem kończę swoją działalność publikacyjną na youthcoders.net, po czym przenoszę się na własnego bloga. To takie info, aby nie było, że zacząłem tu pisać i nagle z niewiadomych powodów wyniosłem się gdzie indziej :)
|