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

0x08 graphic

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;

0x08 graphic
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

0x08 graphic

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

0x08 graphic

Działanie instrukcji continue

0x08 graphic

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