8. INSTRUKCJE POWTARZAJĄCE
8.1. Instrukcja while-do
Instrukcje powtarzające znajdują zastosowanie, gdy działanie programu opiera się na algorytmie iteracyjnym, w którym trzeba wielokrotnie powtarzać jakąś instrukcję lub sekwencję instrukcji.
Jedną z trzech instrukcji powtarzających Turbo Pascala jest instrukcja while-do (po polsku: dopóki-wykonuj) :
while wyr_rel do begin
instrukcja_1;
instrukcja_2;
{---------}
instrukcja_N;
end;
.Dopóki wyrażenie relacyjne po słowie while jet prawdziwe (ma wartość True), wewnętrzny ciąg instrukcji jest cyklicznie powtarzany. Kolejny cykl nie zostanie wykonany i instrukcja zakończy działanie, gdy wyrażenie po while przestanie być prawdziwe (przyjmie wartość False).
Uwaga: Prawdziwość wyrażenia po while warunkiem rozpoczęcia kolejnego cyklu. W przypadku, gdy w chwili rozpoczęcia działania instrukcji wyrażenie po while nie jest prawdziwe, wewnętrzna sekwencja instrukcji nie wykona się w ogóle!
Przykład: Przekształcenie liczby dziesiętnej na jej zapis dwójkowy.
Algorytm: Metoda polega na wielokrotnym dzieleniu całkowitym danej liczby dziesiętnej, a następnie kolejno otrzymywanych ilorazów, przez 2. Otrzymywane wartości reszty (1 lub 0) są kolejnymi pozycjami poszukiwanego zapisu dwójkowego, w porządku od najmłodszej do najstarszej pozycji. Proces kończy się, gdy kolejny iloraz jest zerowy:
Na przykład przekształcenie liczby 12 przebiega, jak następuje:
Krok 1: 12 mod 2 = 0, 12 div 2 = 6
Krok 2: 6 mod 2 = 0, 6 div 2 = 3
Krok 3: 3 mod 2 = 1, 3 div 2 = 1
Krok 4: 1 mod 2 = 1, 1 div 2 = 0
W wyniku otrzymujemy: 1 1 0 0
Odpowiedni program z zastosowaniem instrukcji while-do pokazano poniżej ('#8' jest znakiem cofnięcia kursora).
program Dec_bin; {Przekształca liczbę dziesiętną na dwójkową.} uses Crt; var D,R:Word; begin Clrscr; Write('Jaka liczba dziesietna? '); Readln(D); Write('Binarny zapis liczby: '); GotoXY(Wherex+16,Wherey); while D<>0 do begin R:=D mod 2; D:=D div 2; Write(R,#8#8); {pisanie reszt wspak} end; Readln; end. |
8.2. Instrukcja powtarzająca repeat-until
Zapis instrukcji repeat-until (po polsku: powtarzaj-aż) wygląda, jak następuje:
repeat
instrukcja_1;
instrukcja_2;
{----}
instrukcja_N;
until wyrażenie_relacyjne;
Działanie omawianej instrukcji pokazuje graf na rysunku:
|
Uwaga: Prawdziwość warunku po until jest warunkiem zakończenia instrukcji.
Przykład: Generacja 6 liczb losowych z przedziału 1..49 za pomocą funkcji Random.
program Totek;
uses Crt;
var R,J : Byte;
begin
Clrscr;
J:=0;
Randomize;
repeat
R:=1+Random(49);
Write(R:3);
J:=J+1;
until J=6;
Readln;
end.
Poniżej pokazano wersję programu, która uniemożliwia wystąpienie w serii 6 wylosowanych liczb losowych dwóch lub więcej takich samych wartości.
program Totek_1;
uses Crt;
var R,R1,R2,R3,R4,R5,R6,J:Byte;
begin
Clrscr;
J:=1;
R1:=0; R2:=0; R3:=0; R4:=0; R5:=0; Randomize;
repeat
R:=1+Random(49);
if(R=R1)or(R=R2)or(R=R3)or(R=R4)or(R=R5)
then Continue;
if J=1 then R1:=R;
if J=2 then R2:=R;
if J=3 then R3:=R;
if J=4 then R4:=R;
if J=5 then R5:=R;
if J=6 then R6:=R;
J:=J+1;
until J>6;
Write(R1:3,R2:3,R3:3,R4:3,R5:3,R6:3);
Readln;
end.
Przykład: Program obliczający potęgę
przy całkowitych wartościach wykładnika
program Power;
uses Crt;
var X,Wynik:Real;
Wykl,J:Integer;
begin
Clrscr;
Write('Podaj podstawe: ');
Readln(X);
Write('Podaj calkowity wykladnik: ');
Readln(Wykl);
Wynik:=1;
if Wykl<>0 then begin
J:=0;
repeat
J:=J+1;
Wynik:=Wynik*X;
until J=Abs(Wykl);
end;
if Wykl<0 then Wynik:=1.0/Wynik;
Write('Wynik: ',Wynik:0:6);
Readln;
end.
8.3. Instrukcja powtarzająca for-to-do
Ogólny zapis tej instrukcji jest następujący:
for J:=w1 to w2 do begin
instrukcja_1;
instrukcja_2;
{----}
instrukcja_N;
end;
Instrukcja for jest szczególnie przydatna w sytuacji, gdy wymagana liczba powtórzeń jest określona. Wynika to z faktu, że instrukcja for posiada wewnętrzny mechanizm liczenia cykli pracy Tak zwana zmienna sterująca (nazwana tutaj J), służy jako licznik powtórzeń.
Działanie instrukcji for
|
Przykład: Program obliczający wartość funkcji silnia.
program Silnia;
uses Crt;
var Arg,J:Byte;
S:Longint;
begin
Clrscr;
Write('Podaj argument silni <13: ');
Readln(Arg);
if Arg>12 then S:=0
else begin
S:=1;
for J:=1 to Arg do S:=S*J;
end;
if S=0 then Write('Argument za duzy!')
else
Write('Silnia liczby ',Arg,' wynosi ',S);
Readln;
end.
8.4. Instrukcje break i continue
Tych dwóch instrukcji można używać wyłącznie wewnątrz instrukcji powtarzających, gdzie wykonywane są warunkowo, jako składowe instrukcji if-then lub if-then-else.
Rysunek poniżej wyjaśnia działanie instrukcji break (po polsku: przerwij).. Instrukcja ta powoduje natychmiastowe przerwanie działania i zakończenie instrukcji powtarzającej, wewnątrz której została uruchomiona.
Działanie instrukcji break
Działanie instrukcji continue
Przykład
Program piszący odwrotności liczb losowych
program Ex8_5; {Wyprowadza na ekran 20 odwrotności liczb losowych z zakresu 0..99.} uses Crt; var R:Word; X:Real; begin Clrscr; J:=0; repeat R:=Random(100); if R=0 then continue; X:=1.0/R; Writeln(X:8:6); J:=J+1; until J=20; end.
|
8.5. Obliczanie wartości funkcji metodą iteracyjną Newtona.
Isaac Newton (1642-1727) wymyślił iteracyjny sposób obliczania wartości funkcji. W zastosowaniu do pierwiastka kwadratowego z liczby A jego metoda prowadzi do uzyskania wzoru:
Xj=(Xj-1*Xj-1+A)/(2*Xj-1);
gdzie Xj jest j-tym przybliżeniem wyniku, a Xj-1 poprzednim przybliżeniem wyniku.
Dzięki własnościom operatora przypisania wzór ten w Turbo Pascalu przybiera postać następującej instrukcji:
X:=(X*X+A)/(2*X);
Przykład
Obliczanie pierwiastka kwadratowego metodą Newtona
program Ex8_6;
{Oblicza pierwiastek kwadratowy z A metodą Newtona.}
uses Crt;
const Eps=1E-7;
var A,X,Xp:Real;
begin
Clrscr;
Write('Podaj argument pierwiastka: ');
Readln(A);
if A<0 then X:=-1 else {przypadki szczególne}
if A=0 then X:=0
else begin
Writeln(#10,'Kolejne aproksymacje:',#10);
X:=A/2; {pierwsze przybliżenie}
Writeln(X:20:9);
repeat {obliczenia iteracyjne}
Xp:=X; {zapamiętanie poprzedniego X}
X:=(X*X+A)/(2*X); {wzór Newtona}
Writeln(X:20:9); {druk wyników pośrednich}
until Abs(X-Xp)<Eps;{warunek zakończenia}
end;
if X=-1 then Write('Argument ujemny !?')
else Write('Wynik: ',X:20:9);
Readln;
end.
Poniżej pokazano postać wydruku wyników, otrzymaną dla argumentu A=2.
Podaj argument pierwiastka: 2
Kolejne aproksymacje:
1.000000000
1.500000000
1.416666667
1.414115686
1.414213562
1.414213562
8.6. Wyznaczanie wartości funkcji sinus metodą sumowania wyrazów szeregu
Funkcję sin(x) można rozwinąć w szereg:
sin(x)=x-x3/3!+x5/5!-x7/7!+ ...
gdzie argument x jest wartością kąta w radianach.
Przekształcić powyższe wyrażenie, by uniknąć odrębnego obliczania wartości każdego kolejnego wyrazu szeregu jako ilorazu xk/k! .
Wprowadzamy pomocniczą zmienną całkowitą k. Na początku k=1, a przy obliczaniu kolejnych wyrazów k przyjmuje wartości nieparzyste:
k = 1, 3, 5, 7 ...
Przy tych założeniach, każdy kolejny wyraz wi+1 (z wyjątkiem pierwszego równego x), można wyznaczyć z poprzedniego wi, jako:
wi+1=(-x2/k(k-1))wi
co w Pascalu przyjmie postać instrukcji:
W:=-W*(X*X)/(K*(K-1));
Przykład
Program obliczający wartość funkcji sinus
program Ex8_7;
{Oblicza sinus metodą sumy szeregu.}
uses Crt;
const Eps=1E-9; {założona dokładność}
var X,W,S:Real;
K:Word;
begin
Clrscr;
Write('Podaj kat w radianach: ');
Readln(X); {odczyt argumentu}
if X>2*Pi then repeat
{normalizacja kąta dla X>0)
X:=X-2*Pi;
until X<2*Pi;
if X<-2*Pi then repeat
{normalizacja kąta dla X<0)
X:=X+2*Pi;
until X>=0;
K:=1; W:=X; S:=X; {wartości początkowe}
while Abs(W)>=Eps do begin
K:=K+2; {nowa wartość K}
W:=-W*X*X/(K*(K-1)) {kolejny wyraz}
S:=S+W{dodanie wyrazu do sumy}
end;
Writeln('Wynik:' ,S:0:9);
Readln;
end.
53
wyrażenie
relacyjne
FALSE
instrukcja_1
instrukcja_2
. . .
instrukcja_n
.
end
begin
TRUE
POCZĄTEK
KONIEC
wyrażenie
relacyjne
FALSE
instrukcja_1
instrukcja_2
. . .
instrukcja_n
.
until
repeat
TRUE
POCZĄTEK
KONIEC
J < = w2
TRUE
instrukcja_1
instrukcja_2
. . .
instrukcja_n
.
FALSE
POCZĄTEK
KONIEC
J: = w1
J: = J + 1
w1 > w2
TRUE
FALSE
wyrażenie
relacyjne
FALSE
instrukcja_1;
instrukcja_2;
. . .
if (war) then break;
instrukcja_k;
. . .
instrukcja_n;
.
end
begin
TRUE
POCZĄTEK
KONIEC
wyrażenie
relacyjne
FALSE
instrukcja_1;
instrukcja_2;
if (war) then
continue;
instrukcja_k;
instrukcja_n;
.
end
begin
TRUE
POCZĄTEK
KONIEC