Общие правила организации циклов
Цикл — это фрагмент программы, повторяемый многократно. В Паскале три оператора цикла — while, repeat и for. В принципе, без них можно обойтись, поскольку любой цикл можно реализовать с помощью условного оператора if и оператора перехода goto, но операторы цикла гораздо удобнее и нагляднее. У каждого из них есть предпочтительная область применения.
Все циклы имеют схожую структуру (рис. 2.1). Операторы, ради многократного выполнения которых организуется цикл, называются телом цикла. Остальные операторы служат для управления процессом повторения вычислений: это начальные установки, проверка условия продолжения цикла и модификация параметра цикла. Один проход цикла называется итерацией.
На этапе начальных установок (до входа в цикл) задаются значения переменных, которые в нем используются. Эти значения могут задаваться явно или неявно.
Цикл завершается, если условие его продолжения не выполняется. Возможно принудительное завершение как текущей итерации (для этого применяется процедура continue), так и цикла в целом (процедура break и оператор goto). Передавать управление извне внутрь цикла не рекомендуется, потому что при этом не выполнятся начальные установки. Иными словами, выйти из цикла можно в любой момент, а войти — только в начало (примерно как в самолете).
2.1 Цикл с предусловием while
В цикле с предусловием проверка условия продолжения цикла выполняется перед телом цикла (рис. 2.1,а). Если при входе в цикл условие не выполняется, он не будет выполнен ни разу.
Оператор цикла имеет вид
while выражение dо оператор
Рис. 2.1. Структурная схема операторов цикла:
а — цикл с предусловием; б — цикл с постусловием
2.2 Цикл с постусловием repeat
Оператор цикла с постусловием реализует структурную схему, приведенную на рис. 2.1,б, и имеет вид
repeat
тело цикла
until выражение
В отличие от цикла while, этот цикл будет выполняться, пока ложно логическое выражение, указанное после слова until. Как только результат выражения станет истинным, произойдет выход из цикла. Вычисление выражения выполняется в конце каждой итерации цикла. Тело цикла заключено между служебными словами repeat и until, поэтому дополнительно заключать его между ключевыми словами begin и end не требуется.
Цикл repeat применяется в тех случаях, когда тело цикла необходимо обязательно выполнить хотя бы один раз: например, если в нем вводятся данные и выполняется их проверка. Если же такой необходимости нет, предпочтительнее пользоваться циклом с предусловием.
2.3 Цикл с параметром for
Параметром цикла называется переменная, которая используется при проверке условия продолжения цикла и принудительно изменяется на одну и ту же величину на каждой итерации. Если параметр цикла целочисленный, он называется счетчиком цикла. В циклах for языка Паскаль используется счетчик, который автоматически либо увеличивается, либо уменьшается на единицу. Соответственно, есть две формы записей этого цикла:
for параметр := выражение_1 to выражение_2 do оператор
for параметр : = выражение_2 downto выражение_1 do оператор
Параметр цикла должен быть порядкового типа. Напомним, что к порядковым из стандартных типов относятся целые, символьный и логические типы.
Выражения должны быть совместимы по присваиванию с переменной цикла. Они вычисляются один раз до входа в цикл. Оператор for реализован в Паскале как цикл с предусловием. Таким образом, если в первой форме выражение_1 будет больше, чем выражение_2, а во второй — меньше, тело такого цикла не будет выполнено ни разу.
Источник
Ëåêöèÿ
äîöåíòà êàôåäðû ÈÂÒ Ãðîäíåíñêîãî ãîñóíèâåðñèòåòà
êàíä. òåõí. íàóê Ëèâàê Åëåíû Íèêîëàåâíû
ÎÐÃÀÍÈÇÀÖÈß ÖÈÊËÎÂ
- Â ëåêöèè:
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíä óñëîâíîãî ïåðåõîäà è ðåãèñòðà ecx/cx.
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíäû áåçóñëîâíîãî ïåðåõîäà jmp è ðåãèñòðà ecx/cx.
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ ñïåöèàëüíûõ êîìàíä.
- Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíäû loop.
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíä loope/loopz.
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíä loopne/loopnz.
Îðãàíèçàöèÿ äëèííûõ öèêëîâ
Êàê è â ëþáîì ÿçûêå ïðîãðàììèðîâàíèÿ, â ÿçûêå Assembler cóùåñòâóåò íåñêîëüêî ñïîñîáîâ îðãàíèçàöèè öèêëè÷åñêîãî ïîâòîðåíèÿ ôðàãìåíòà ïðîãðàììû.
Êàæäûé èç ñïîñîáîâ èìååò ñâîè îñîáåííîñòè, ïîýòîìó äëÿ ýôôåêòèâíîé ðåàëèçàöèè êîíêðåòíîé çàäà÷è ñëåäóåò èñïîëüçîâàòü íàèáîëåå ïîäõîäÿùèé ñïîñîá.
Ðàññìîòðèì îñîáåííîñòè ñïîñîáîâ îðãàíèçàöèè öèêëîâ.
Ïåðâûé ñïîñîá — îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíä óñëîâíîãî ïåðåõîäà è ðåãèñòðà ecx/cx .
Íàïîìíèì, ÷òî â àðõèòåêòóðå ìèêðîïðîöåññîðîâ Intel ðåãèñòð ecx/cx èìååò îïðåäåëåííîå ôóíêöèîíàëüíîå íàçíà÷åíèå âûïîëíÿåò ðîëü ñ÷åò÷èêà.
Åñëè íåêîòîðóþ ãðóïïó êîìàíä íåîáõîäèìî ïîâòîðèòü îïðåäåëåííîå êîëè÷åñòâî ðàç, öèêë ìîæíî îðãàíèçîâàòü ñëåäóþùèì îáðàçîì:
1) ïîìåñòèòü â ðåãèñòð ecx/cx êîëè÷åñòâî ïîâòîðåíèé;
2) ïåðâóþ êîìàíäó òåëà öèêëà îòìåòèòü ìåòêîé;
3) ïîñëå âûïîëíåíèÿ òåëà öèêëà óìåíüøèòü ñîäåðæèìîå ðåãèñòðà ecx/cx íà 1;
4) âûïîëíèòü ñðàâíåíèå ñîäåðæèìîãî ðåãèñòðà ecx/cxñ íóëåì;
5) â ñëó÷àå, åñëè ecx/cx≠ 0, îñóùåñòâèòü ïåðåõîä íà ìåòêó, èíà÷å âûïîëíÿòü ñëåäóþùóþ çà òåëîì öèêëà êîìàíäó.
Ñõåìà ðåàëèçàöèè áóäåò âûãëÿäåòü òàêèì îáðàçîì:
mov cx,N
CYCL:
<òåëî öèêëà>
dec cx
cmp cx,0
jne CYCL
…
Âíèìàíèå. Íåîáõîäèìî
îáðàùàòü âíèìàíèå íà âûïîëíåíèå «ïóñòîãî» öèêëà.Åñëè âäðóã íà÷àëüíîå çíà÷åíèå â ðåãèñòðå cx ðàâíî
íóëþ, òî ïîñëå óìåíüøåíèÿ íà åäèíèöó, ñîäåðæèìûì ðåãèñòðà ñòàíåò ÷èñëî FFFFh (-1 â äåñÿòè÷íîé ñèñòåìå ñ÷èñëåíèÿ).
 ðåçóëüòàòå öèêë ïîâòîðèòñÿ åùå 65535 ðàç (èëè 4 294 967 295 ðàç ïðè èñïîëüçîâàíèè ðåãèñòðà ecx). Ïîýòîìó
ñëåäóåò âñåãäà ïðîâåðÿòü ñîäåðæèìîå ðåãèñòðà ecx/cx äëÿ ïðåäîòâðàùåíèÿ âûïîëíåíèÿ «ïóñòîãî» öèêëà.
Òàêóþ ïðîâåðêó ëåãêî îðãàíèçîâàòü ñ ïîìîùüþ êîìàíäû óñëîâíîãî ïåðåõîäà
jcxz/jecxz.
Ñèíòàêñèñ êîìàíäû:
jcxz <ìåòêà ïåðåõîäà>
Ëèáî â ñëó÷àå íåîáõîäèìîñòè èñïîëüçîâàíèÿ ðàñøèðåííîãî ðåãèñòðà
jecxz <ìåòêà ïåðåõîäà>
Ïåðåâîä-ðàñøèôðîâêà àááðåâèàòóðû íàçâàíèÿ êîìàíäû — Jump if cx is Zero — ïåðåõîä, åñëè cx ðàâíî íóëþ.
Çàìå÷àíèå. Êîìàíäà jcxz/jecxz ìîæåò àäðåñîâàòü òîëüêî êîðîòêèå ïåðåõîäû (íà 128 èëè íà +127 áàéò îò ñëåäóþùåé çà
íåé êîìàíäû).
Èòàê, ñõåìà îðãàíèçàöèè öèêëà ñ ïðåäîòâðàùåíèåì âûïîëíåíèÿ «ïóñòîãî» öèêëà
mov cx,N
jcxz Exit
CYCL:
<òåëî öèêëà>
dec cx
cmp cx,0
jne CYCL
Exit: . . .
Âòîðîé ñïîñîá — îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíäû áåçóñëîâíîãî ïåðåõîäà jmp è ðåãèñòðà ecx/cx.
Öèêë ìîæíî îðãàíèçîâàòü è ñëåäóþùèì îáðàçîì:
1) ïîìåñòèòü â ðåãèñòð ecx/cx êîëè÷åñòâî ïîâòîðåíèé;
2) îñóùåñòâèòü ïðîâåðêó íà «ïóñòîé» öèêë êîìàíäîé jecxz/jcxz <ìåòêà ïåðåõîäà>
3) ýòó êîìàíäó ïðîâåðêè îòìåòèòü ìåòêîé íà÷àëà öèêëà;
4) ïîñëå âûïîëíåíèÿ òåëà öèêëà óìåíüøèòü ñîäåðæèìîå ðåãèñòðà ecx/cx íà 1;
5) âûïîëíèòü áåçóñëîâíûé ïåðåõîä íà íà÷àëî öèêëà.
Ñõåìà ðåàëèçàöèè áóäåò âûãëÿäåòü òàêèì îáðàçîì:
mov cx,N
CYCL:
jcxz Exit
<òåëî öèêëà>
dec cx
jmp CYCL
Exit: . . .
Îáðàòèì âíèìàíèå íà òî, ÷òî çäåñü êîìàíäà jcxz èãðàåò äâîéíóþ ðîëü. Âî-ïåðâûõ, ïðåäîòâðàùàåò âûïîëíåíèå «ïóñòîãî» öèêëà, è, âî-âòîðûõ,
îòñëåæèâàåò îêîí÷àíèå öèêëà.
Òðåòèé ñïîñîá — îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ ñïåöèàëüíûõ êîìàíä.
Çàìåòèì, ÷òî â îïèñàííûõ ïåðâûõ äâóõ ñïîñîáàõ îðãàíèçàöèè öèêëà áîëüøèíñòâî îïåðàöèé
âûïîëíÿþòñÿ âðó÷íóþ (äåêðåìåíò ðåãèñòðà cx, ñðàâíåíèå cx ñ íóëåì, ïåðåõîä íà íà÷àëî öèêëà).
Ó÷èòûâàÿ âàæíîñòü öèêëîâ (ïðàêòè÷åñêè íè îäíà ïðîãðàììà íå îáõîäèòñÿ áåç òàêèõ êîíñòðóêöèé)
ðàçðàáîò÷èêè ñèñòåìû êîìàíä ìèêðîïðîöåññîðà ââåëè ñïåöèàëüíûå êîìàíäû, îáëåã÷àþùèå (ñîêðàùàþùèå) ïðîãðàììèðîâàíèå öèêëè÷åñêèõ ó÷àñòêîâ
ïðîãðàìì.
- Ýòî êîìàíäû
- loop <ìåòêà ïåðåõîäà>
loope/loopz <ìåòêà ïåðåõîäà>
loopne/loopnz <ìåòêà ïåðåõîäà>
Îáðàòèì âíèìàíèå, ýòè êîìàíäû òàêæå èñïîëüçóþò ðåãèñòð ecx/cx êàê ïàðàìåòð (ñ÷åò÷èê) öèêëà.
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíäû loop
 ïåðåâîäå Loop îçíà÷àåò «ïåòëÿ», èëè äðóãèìè ñëîâàìè «ïîâòîðèòü öèêë».
Ñèíòàêñèñ êîìàíäû:
loop <ìåòêà ïåðåõîäà>
Ðàáîòà êîìàíäû çàêëþ÷àåòñÿ â âûïîëíåíèè ñëåäóþùèõ äåéñòâèé:
1) óìåíüøåíèå çíà÷åíèÿ ðåãèñòðà ecx/cx íà 1;
2) ñðàâíåíèå ðåãèñòðà ecx/cxñ íóëåì:
åñëè ecx/cx= 0, òî îñóùåñòâëÿåòñÿ âûõîä èç öèêëà, ò.å. óïðàâëåíèå ïåðåäàåòñÿ íà ñëåäóþùóþ ïîñëå loop êîìàíäó; èíà÷å
— óïðàâëåíèå ïåðåäàåòñÿ íà ìåòêó ïåðåõîäà (öèêë ïîâòîðÿåòñÿ).
Ïîðÿäîê îðãàíèçàöèè öèêëà ñ ïîìîùüþ êîìàíäû loop :
1) â ðåãèñòð cx ïîìåñòèòü çíà÷åíèå, ðàâíîå êîëè÷åñòâó ïîâòîðåíèé;
2) óñòàíîâèòü ìåòêó íà ïåðâóþ êîìàíäó òåëà öèêëà;
3) âûïîëíèòü êîìàíäó loop <ìåòêà ïåðåõîäà>.
Ñõåìà ðåàëèçàöèè âûãëÿäèò ñëåäóþùèì îáðàçîì:
mov cx,N
jcxz Exit
CYCL :
<òåëî öèêëà>
loop CYCL
Exit : . . .
Îáðàòèì âíèìàíèå òàêæå íà òî, ÷òî ïîñëå âûõîäà èç öèêëà ñîäåðæèìîå ðåãèñòðà cx âñåãäà ðàâíî íóëþ.
Ïðèìåð 1.
Íåîáõîäèìî ïîäñ÷èòàòü ñóììó ýëåìåíòîâ ìàññèâà
masm
model small
.stack 128
.data
size equ 10
mas db size dup (?)
sum dw ?
.code
start: < íà÷àëî ïðîãðàììû>
< ââîä ýëåìåíòîâ ìàññèâà>
mov cx,size ; ÷èñëî ïîâòîðåíèé öèêëà
lea bx,mas
xor ax,ax ; â ax áóäåì íàêàïëèâàòü ñóììó
begin: add ax,[ bx ]
inc bx ; ïåðåõîä ê ñëåäóþùåìó ýëåìåíòó (ðàçìåð ýëåìåíòà – 1 áàéò)
loop begin
mov sum,ax
. . .
end start
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíä loope / loopz.
Çàìåòèì, ÷òî êîìàíäû loope è loopz àáñîëþòíûå ñèíîíèìû. Èñïîëüçîâàòü ìîæíî ëþáóþ èç íèõ.
Ñèíòàêñèñ êîìàíä:
loope <ìåòêà ïåðåõîäà>
loopz <ìåòêà ïåðåõîäà>
Ïðè èñïîëüçîâàíèè ýòèõ êîìàíä öèêë ïîâòîðÿåòñÿ äî òåõ ïîð, ïîêà cx ≠ 0 è zf = 1. Âûõîä èç öèêëà
îñóùåñòâëÿåòñÿ ïðè âûïîëíåíèè îäíîãî èç äâóõ óñëîâèé:
cx = 0 èëè zf = 0.
Ðàáîòà êîìàíä çàêëþ÷àåòñÿ â âûïîëíåíèè ñëåäóþùèõ äåéñòâèé:
1) óìåíüøåíèå çíà÷åíèÿ ðåãèñòðà ecx/cx íà 1;
2) ñðàâíåíèå ðåãèñòðà ecx/cx ñ íóëåì: åñëè (ecx/cx) = 0, îñóùåñòâëÿåòñÿ âûõîä èç öèêëà;
3) àíàëèç ñîñòîÿíèÿ ôëàãà íóëÿ zf: åñëè zf = 0, îñóùåñòâëÿåòñÿ âûõîä èç öèêëà.
Òàêèì îáðàçîì, öèêë ïîâòîðÿåòñÿ, åñëè cx ≠ 0 è zf = 1.
Íàïîìíèì, ÷òî ôëàã íóëÿ zf ïðèíèìàåò çíà÷åíèå 0, êîãäà ñðàâíèâàåìûå îïåðàíäû íå ðàâíû ìåæäó ñîáîé, è çíà÷åíèå 1, åñëè
îïåðàíäû ñîâïàäàþò. Äëÿ íàãëÿäíîñòè èçîáðàçèì ýòî ñõåìàòè÷åñêè:
cmp îï1, îï2
îï1 = îï2 ⇒ zf=1
îï1 ≠ îï2 ⇒ zf=0
Ïîýòîìó, èñïîëüçóÿ ýòîò ôëàã â êà÷åñòâå èíäèêàòîðà óäîáíî îðãàíèçîâàòü äîñðî÷íûé (äî
òîãî, êàê çíà÷åíèå cx ñòàíåò 0) âûõîä èç öèêëà.
Ïîðÿäîê îðãàíèçàöèè öèêëà ñ ïîìîùüþ êîìàíäû loope :
1) â ðåãèñòð cx ïîìåñòèòü çíà÷åíèå, ðàâíîå êîëè÷åñòâó ïîâòîðåíèé;
2) óñòàíîâèòü ìåòêó íà ïåðâóþ êîìàíäó òåëà öèêëà;
3) èñïîëüçîâàòü êîìàíäó cmp äëÿ ñðàâíåíèÿ îïåðàíäîâ (çäåñü áóäåò óñòàíîâëåí ôëàã íóëÿ);
4) âûïîëíèòü êîìàíäó loope <ìåòêà ïåðåõîäà>.
Ñõåìà ðåàëèçàöèè âûãëÿäèò ñëåäóþùèì îáðàçîì:
mov cx,N
jcxz Exit
CYCL :
<òåëî öèêëà>
cmp <îï1>,<îï1>
loope CYCL
Exit: . . .
Ñîâåò. Òàê êàê ôëàã íóëÿ ïðèíèìàåò çíà÷åíèå 0 â ñëó÷àå íåñîâïàäåíèÿ îïåðàíäîâ è,
ñîîòâåòñòâåííî, âûõîä èç öèêëà îñóùåñòâëÿåòñÿ èìåííî ïðè íåñîâïàäåíèè îïåðàíäîâ, êîìàíäû loope/loopz óäîáíî
èñïîëüçîâàòü äëÿ ïîèñêà ïåðâîãî ýëåìåíòà ïîñëåäîâàòåëüíîñòè, îòëè÷íîãî îò çàäàííîé âåëè÷èíû.
Ïðèìåð 2.
Íåîáõîäèìî ïðîâåðèòü, ñîâïàäàþò ëè äâà ìàññèâà.
Î÷åâèäíî, ÷òî ïîâòîðÿþùèìñÿ ôðàãìåíòîì ïðîãðàììû áóäåò ó÷àñòîê êîäà, âûïîëíÿþùèé ñðàâíåíèå
ñîîòâåòñòâóþùèõ ýëåìåíòîâ ìàññèâîâ. Îáðàòèì âíèìàíèå íà òî, ÷òî äîñðî÷íûé âûõîä
èç öèêëà íåîáõîäèìî áóäåò îñóùåñòâèòü, êàê òîëüêî áóäåò íàéäåíà ïåðâàÿ
íåñîâïàäàþùàÿ ïàðà. Îñòàëüíûå ýëåìåíòû ìàññèâîâ ñðàâíèâàòü äàëåå íåò ñìûñëà.
Ïîýòîìó ïðè ðåàëèçàöèè äàííîé çàäà÷è äëÿ îðãàíèçàöèè öèêëà óäîáíî èñïîëüçîâàòü
êîìàíäó loope/loopz.
Ðåàëèçóåì ôðàãìåíò ïðîãðàììû, îñóùåñòâëÿþùåé ïðîâåðêó äåñÿòèýëåìåíòíûõ ìàññèâîâ, ýëåìåíòû
êîòîðûõ — äâóõáàéòîâûå ÷èñëà. Ðåçóëüòàò â âèäå ïðèçíàêà 0 èëè 1 çàïèøåì â ïîëå rez. Ïóñòü
ïðèçíàêîì ñîâïàäåíèÿ áóäåò çíà÷åíèå 1, ïðèçíàêîì íåñîâïàäåíèÿ —0.
…
A dw 10 dup (?)
B dw 10 dup (?)
Rez dw ?
…
mov cx, 10;÷èñëî ïîâòîðåíèé öèêëà
<ïðîâåðêà íà «ïóñòîé» öèêë; ïîäãîòîâêà ðåãèñòðîâ>
lea bx, B
mov si, -2
Cycl: mov ax, bx[si+2]
add si,2
cmp ax,A[si]
loope Cycl
;â äàííûé ìîìåíò íåèçâåñòíî, ïî÷åìó ïðîèçîøåë âûõîä èç öèêëà:
;ëèáî cx = 0 (òî åñòü, âñå ïàðû ýëåìåíòîâ ïðîâåðåíû, ðàçëè÷èé íåò)
;ëèáî ôëàã zf = 0 (òî åñòü, íàéäåíà ïàðà íåñîâïàäàþùèõ ýëåìåíòîâ)
cmp cx,0;ïðîâåðêà: ïî÷åìó âûøëè èç öèêëà?
jne No
mov dx,1 ;â dx — ïðèçíàê ñîâïàäåíèÿ
jmp End
No:mov dx,0;â dx — ïðèçíàê íåñîâïàäåíèÿ
End: mov Rez,dx
…
Çàäàíèå. Ðàññìîòðèòå ñàìîñòîÿòåëüíî âîïðîñ î íåîáõîäèìîñòè
ðàçìåðà ïîëÿ Rez, ðàâíîãî 2 áàéòàì, à òàêæå öåëåñîîáðàçíîñòè çàïèñè ïðèçíàêà ïðåäâàðèòåëüíî â ðåãèñòð dx.
Âíåñèòå ñîîòâåòñòâóþùèå èçìåíåíèÿ â òåêñò ïðîãðàììû, äîïèøèòå íåîáõîäèìûå êîìàíäû è âûïîëíèòå ïðîãðàììó.
Îðãàíèçàöèÿ öèêëà ñ ïîìîùüþ êîìàíä loopne/loopnz.
Çàìåòèì, ÷òî êîìàíäû loopne/loopnz ÿâëÿþòñÿ îáðàòíûìè êîìàíäàì loope/loopz.
Loopne è loopnz òàêæå àáñîëþòíûå ñèíîíèìû, èñïîëüçîâàòü ìîæíî ëþáóþ èç íèõ.
Ñèíòàêñèñ êîìàíä:
Loopne <ìåòêà ïåðåõîäà>
loopnz <ìåòêà ïåðåõîäà>
Ïðè èñïîëüçîâàíèè ýòèõ êîìàíä öèêë ïîâòîðÿåòñÿ äî òåõ ïîð, ïîêà
cx ≠ 0 è zf = 0.
Âûõîä èç öèêëà îñóùåñòâëÿåòñÿ ïðè âûïîëíåíèè îäíîãî èç äâóõ óñëîâèé:
cx = 0 èëè zf = 1.
Ðàáîòà êîìàíä çàêëþ÷àåòñÿ â âûïîëíåíèè ñëåäóþùèõ äåéñòâèé:
1) óìåíüøåíèå çíà÷åíèÿ ðåãèñòðà ecx/cx íà 1;
2) ñðàâíåíèå ðåãèñòðà ecx/cx ñ íóëåì: åñëè ( ecx/cx ) = 0,
îñóùåñòâëÿåòñÿ âûõîä èç öèêëà;
3) àíàëèç ñîñòîÿíèÿ ôëàãà íóëÿ zf : åñëè zf = 1,
îñóùåñòâëÿåòñÿ âûõîä èç öèêëà.
Òàêèì îáðàçîì, öèêë ïîâòîðÿåòñÿ, åñëè cx ≠ 0 è zf = 0.
Ïîðÿäîê îðãàíèçàöèè öèêëà ñ ïîìîùüþ êîìàíäû loopne :
1) â ðåãèñòð cx ïîìåñòèòü çíà÷åíèå, ðàâíîå êîëè÷åñòâó ïîâòîðåíèé;
2) óñòàíîâèòü ìåòêó íà ïåðâóþ êîìàíäó òåëà öèêëà;
3) èñïîëüçîâàòü êîìàíäó cmp äëÿ ñðàâíåíèÿ îïåðàíäîâ (çäåñü áóäåò óñòàíîâëåí ôëàã íóëÿ);
4) âûïîëíèòü êîìàíäó Loopne <ìåòêà ïåðåõîäà>.
Ñõåìà ðåàëèçàöèè âûãëÿäèò ñëåäóþùèì îáðàçîì:
mov cx , N
jcxz Exit
CYCL :
<òåëî öèêëà>
cmp <îï1>,<îï1>
loopne CYCL
Exit: . . .
Ñîâåò. Òàê êàê ôëàã íóëÿ ïðèíèìàåò çíà÷åíèå 1 â ñëó÷àå
ñîâïàäåíèÿ îïåðàíäîâ è, ñîîòâåòñòâåííî, âûõîä èç öèêëà îñóùåñòâëÿåòñÿ èìåííî ïðè ñîâïàäåíèè îïåðàíäîâ,
êîìàíäû loopne/loopnz óäîáíî èñïîëüçîâàòü äëÿ ïîèñêà ïåðâîãî ýëåìåíòà ïîñëåäîâàòåëüíîñòè, èìåþùåãî çàäàííóþ âåëè÷èíó.
Ïðèìåð 3.
Íåîáõîäèìî ïðîâåðèòü, åñòü ëè â ìàññèâå íóëåâûå ýëåìåíòû, è âûâåñòè ñîîòâåòñòâóþùåå ñîîáùåíèå.
Î÷åâèäíî, ÷òî ïîâòîðÿþùèìñÿ ôðàãìåíòîì ïðîãðàììû áóäåò ó÷àñòîê êîäà, âûïîëíÿþùèé ñðàâíåíèå
î÷åðåäíîãî ýëåìåíòà ìàññèâà ñ çàäàííûì çíà÷åíèåì — íîëü. Îáðàòèì âíèìàíèå íà òî,
÷òî äîñðî÷íûé âûõîä èç öèêëà íåîáõîäèìî áóäåò îñóùåñòâèòü, êàê
òîëüêî áóäåò íàéäåí ïåðâûé ýëåìåíò ðàâíûé íóëþ, òàê êàê â äàííîì ñëó÷àå çíà÷åíèå
îñòàëüíûõ ýëåìåíòîâ ìàññèâà íàñ èíòåðåñîâàòü óæå íå áóäóò. Ïîýòîìó ïðè
ðåàëèçàöèè äàííîé çàäà÷è äëÿ îðãàíèçàöèè öèêëà ñëåäóåò èñïîëüçîâàòü êîìàíäó loopne/loopnz.
masm
model small
.stack 128
.data
len equ 10 ;êîëè÷åñòâî ýëåìåíòîâ ìàññèâà
mas db len dup (?)
mes _ no db 0dh , 0ah , ‘Â ìàññèâå îòñóòñòâóþò íóëåâûå ýëåìåíòû $’
mes _ yes db 0dh , 0ah , ‘Â ìàññèâå åñòü íóëåâûå ýëåìåíòû $’
. code
start :
mov ax,@data
mov ds,ax
mov cx,len ;÷èñëî ïîâòîðåíèé öèêëà
xor ax,ax
xor si,si
jcxz exit ;ïðîâåðêà íà «ïóñòîé»öèêë
mov si,-1 ;ãîòîâèì si ê àäðåñàöèè ýëåìåíòîâ ìàññèâà
cycl : inc si
cmp mas[si],0 ; ñðàâíèòü î÷åðåäíîé ýëåìåíò mas ñ 0
loopnz cycl
;â äàííûé ìîìåíò íåèçâåñòíî, ïî÷åìó ïðîèçîøåë âûõîä èç öèêëà:
;ëèáî cx = 0 (òî åñòü, íóëåâûõ ýëåìåíòîâ íåò)
;ëèáî ôëàã zf = 1 (òî åñòü, íàéäåí íóëåâîé ýëåìåíò)
mov ah,09h ;ãîòîâèìñÿ ê âûâîäó ñîîáùåíèÿ
jz yes ;ïðîâåðêà: ïî÷åìó âûøëè èç öèêëà?
; åñëè ôëàã zf = 1, òî ïåðåõîä íà ìåòêó Yes, èíà÷å —
lea dx, mes_no ;ñîîáùåíèå, î òîì, ÷òî íåò íóëåâûõ ýëåìåíòîâ
jmp Mes
yes : ;íàéäåí íóëåâîé ýëåìåíò
lea dx , mes_yes ;ñîîáùåíèå, î òîì, ÷òî åcòü íóëåâûå ýëåìåíòû
Mes : int 21h ;âûâîä ñîîáùåíèÿ
mov ax,4c00h
int 21h ;âîçâðàò óïðàâëåíèÿ îïåðàöèîííîé ñèñòåìå
end start
Îðãàíèçàöèÿ äëèííûõ öèêëîâ
Çàìåòèì, ÷òî ñïåöèàëüíûå êîìàíäû îðãàíèçàöèè öèêëà loop , loope / loopz è loopne / loopnz , òàêæå êàê è êîìàíäû
óñëîâíûõ ïåðåõîäîâ, ðåàëèçóþò òîëüêî êîðîòêèå ïåðåõîäû (îò 128 äî +127 áàéò),
òàê êàê äëÿ àäðåñà ïåðåõîäà â êîäå êîìàíä îòâîäèòñÿ òîëüêî îäèí áàéò. Òî åñòü
òåëî öèêëà îãðàíè÷èâàåòñÿ òîëüêî 128 áàéòàìè. Åñëè òåëî öèêëà èìååò áîëüøóþ
äëèíó, öèêë íåîáõîäèìî îðãàíèçîâûâàòü äðóãèì îáðàçîì.
Íàïîìíèì, ÷òî òîëüêî êîìàíäà áåçóñëîâíîãî ïåðåõîäà jmp ïîçâîëÿåò
îñóùåñòâëÿòü äëèííûå ïåðåõîäû, òàê êàê â êîäå êîìàíäû ïîä ñìåùåíèå àäðåñà
ïåðåõîäà îòâîäèòñÿ äâà áàéòà.
Äëÿ îðãàíèçàöèè äëèííûõ öèêëîâ ñëåäóåò èñïîëüçîâàòü êîìàíäû óñëîâíîãî ïåðåõîäà è êîìàíäó jmp.
Ñõåìà ðåàëèçàöèè äëèííîãî öèêëà:
mov cx,N
CYCL:
<òåëî öèêëà>
dec cx
cmp cx,0
je Out
jmp CYCL
Out: . . .
Òî åñòü, äëÿ
îðãàíèçàöèè äëèííîãî öèêëà íåîáõîäèìî «âðó÷íóþ» óìåíüøàòü ñîäåðæèìîå ïàðàìåòðà
(ñ÷åò÷èêà) öèêëà è ñðàâíèâàòü ïîëó÷åííîå çíà÷åíèå ñ íóëåì. Êîãäà âûïîëíåíî
îïðåäåëåííîå êîëè÷åñòâî ïîâòîðåíèé (cx = 0), ñ ïîìîùüþ êîìàíäû óñëîâíîãî ïåðåõîäà
je
ñëåäóåò âûéòè èç öèêëà, èíà÷å — êîìàíäîé áåçóñëîâíîãî ïåðåõîäà jmp íåîáõîäèìî
îñóùåñòâèòü ïåðåõîä íà íà÷àëî öèêëà.
Источник
Циклом называется многократно повторяющаяся последовательность действий (операторов). Цикл – типичная структура, характерная для программ, реализуемых на компьютере. Средства языка C# для организации циклов приводятся в п. 1.7.2, 1.7.3, 1.7.4.
2.1.1. Циклы по счетчику
Рассмотрим вначале циклы по счетчику, т.е. когда количество повторений цикла известно до начала его выполнения.
При организации цикла по счетчику необходимо:
1) выделить повторяющиеся действия и записать их в общем виде;
2) выбрать управляющую переменную цикла. Это может быть какая-либо величина, имеющаяся в постановке задачи, либо используемая специально в качестве счетчика;
3) определить параметры цикла, т.е. начальное и конечное значения управляющей переменной и шаг ее изменения.
Пример 2.1. Пусть требуется вычислить сумму
S = 1 + 2 + 3 + … +100.
Организуем вычисления так, чтобы на каждом шаге выполнялись простые действия, в данном случае это прибавление к сумме очередного слагаемого. Вначале необходимо обнулить переменную, в которой будет накапливаться сумма (s = 0), а затем на каждом шаге добавлять к сумме очередной член, т.е. многократно выполнять операцию
s = s + i, где i = 1, 2, 3, … , 100.
Таким образом, в качестве управляющей переменной цикла в данном случае можно использовать сам член суммы, который изменяется в заданных пределах (от 1 до 100) с заданным шагом 1.
Тогда программа будет иметь следующий вид:
using System;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
int i, s = 0;
for (i = 1; i <= 100; i = i + 1)
s = s + i;
Console.WriteLine(“s = {0}”, s);
Console.ReadKey();
}
}
}
Результат выполнения программы.
Пример 2.2. Вычислить сумму четных чисел от 2 до 20.
Здесь требуется организация цикла по счетчику с управляющей переменной, например, k, изменяющейся с шагом 2 от 2 до 20.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
int k, s = 0;
for (k = 2; k <= 20; k = k + 2)
s = s + k;
Console.WriteLine(“s= {0}”, s);
Console.ReadKey();
}
}
}
Или
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int k = 2, s = 0;
do
{
s = s + k;
k = k + 2;
} while (k <= 20);
Console.WriteLine(“s = {0}”, s);
Console.ReadKey();
}
}
}
Пример 2.3. Вычислить сумму s = 3 + 32 + 33 + … + 38.
На каждом шаге алгоритма необходимо прибавлять к сумме очередное слагаемое (s = s + 3i), где i = 1, 2, 3, … , 8. Вспомним, что операция возведения в степень в языке C# отсутствует, поэтому следующий член суммы будем получать из предыдущего домножением его на 3. В качестве управляющей переменной цикла можно использовать показатель степени, изменяющийся в заданных пределах от 1 до 8 с заданным шагом, равным 1. Программа, таким образом, будет иметь следующий вид (здесь и далее приводится только алгоритмическая часть проекта):
int s = 0, a = 1;
for (int i = 1; i <= 8; i = i + 1)
{
a = a * 3;
s = s + a;
}
Console.WriteLine(“s = {0}”, s);
Console.ReadKey();
Замечание. Выражение для получения очередного члена последовательности из предыдущего называется рекуррентной формулой.
Пример 2.4. Вычислить s = 5/8 + 7/10 + … + 31/34.
Для организации цикла в этом случае можно использовать числитель, изменяющийся от 5 до 31 с шагом 2, а знаменатель выразить через числитель (он отличается от числителя на 3):
double s = 0;
for (int a = 5; a <= 31; a = a + 2)
{
s = s + a / (a + 3.0);
}
Console.WriteLine(“s = {0}”, s);
Console.ReadKey();
Замечание. При делении целого на целое результат получается целый (дробная часть теряется). Поэтому при вычислении знаменателя второе слагаемое записано в виде вещественного числа. Знаменатель будет теперь иметь тип double, и результат деления будет иметь тип double.
Возможны и другие способы организации вычислений. Предложите их самостоятельно.
Для организации цикла в данном примере можно использовать специальную переменную (счетчик), определяющую номер итерации. Для определения общего количества повторений цикла (n) можно использовать формулу
n = (iкон – iнач)/h+1.
В данном случае при iкон = 31, iнач = 5, h = 2 получаем n = 14. Тогда программа будет иметь вид
double s = 0, a;
int n;
double xh = 5, xk = 31, h = 2;
a = xh;
n = (int)((xk – xh) / h + 1);
for (int i = 1; i <= n; i = i + 1)
{
s = s + a / (a + 3);
a = a + h;
}
Console.WriteLine(“s = {0}”, s);
Console.ReadKey();
Здесь при вычислении n использовано явное преобразование типа указанием типа в скобках перед выражением, т.к. результат метода Round (округление) имеет тип double.
Пример 2.5. Вычислить .
double s = 0.0, a;
int i, p = 1;
for (i = 1; i <= 25; i = i + 1)
{
p = -p;
a = p * 2 * i / (i * i + 2.0);
s = s + a;
}
s = (2.0 / 3.0) * s;
Console.WriteLine(“{0:f4}”,s);
Console.ReadKey();
Замечание. В программе использован тот же прием согласования типов, что и в предыдущем примере. Порядок вычислений и тип результата операций в выражении правой части при вычислении члена суммы a следующий: вычисляется p * 2 – тип результата int, результат этой операции умножается на i, тип результата int, вычисляется знаменатель (выражение в скобках) в следующем порядке: вычисляется i * i – результат операции имеет тип int и к этому результату прибавляется вещественное число 2.0 (по умолчанию типа double), знаменатель после вычисления имеет тип double. Таким образом значение выражения правой части имеет тип double.
Пример 2.6. Получить таблицу значений функции при изменении x в пределах от xh = -2.5 до xk = 2.5 с шагом h = 0.5.
const double xh = -2.5, xk = 2.5, h = 0.5;
double x, y;
int i, n;
n = (int)((xk – xh) / h + 1);
x = xh;
for (i = 1; i <= n; i = i + 1)
{
y = Math.Pow(x, 2) + 0.5 * x;
Console.WriteLine(“x = {0:f2}ty = {1:f2}”, x, y);
x = x + h;
}
Console.ReadKey();
Замечания.
1. Здесь для определения количества значений аргумента при его изменении в пределах от xh до xk c шагом h использована формула n =(xk – xh)/h + 1.В программе для получения в качестве n целого значения использовано явное преобразование типа указанием его в скобках перед выражением.
2. Для вычисления использован метод Pow класса Math.
3. Наличие символа t в строке формата обеспечивает табуляцию при выводе каждого значения y, что обеспечивает большую наглядность результата. (Этого эффекта можно добиться и другими способами. Предложите их самостоятельно.)
Второй вариант программы.Используется цикл do.
const double xh = -2.5, xk = 2.5, h = 0.5;
double x, y;
x = xh;
do
{
y = Math.Pow(x, 2) + 0.5 * x;
Console.WriteLine(“x = {0:f2}ty = {1:f2}”, x, y);
x = x + h;
}
while (x < xk + 0.0001);
Console.ReadKey();
Здесь при проверке условия while сравнение текущего значения x осуществляется с величиной несколько большей верхней границы его изменения. Это связано с особенностями представления в памяти компьютера вещественных чисел. Вещественные числа представляются неточно и в результате многократного выполнения арифметических операций может накопиться ошибка, так что последнее значение x может быть несколько больше xk и при отсутствии второго слагаемого в условии не попадет в таблицу.
Пример 2.7. Вычислить p = n! при n = 8.
Вычисление факториала можно организовать в цикле, домножая каждый раз значение p на очередной сомножитель.
const int n = 8;
int p = 1;
for (int i = 2; i <= n; i++)
{
p = p * i;
}
Console.WriteLine(“p = {0:d}”, p);
Console.ReadKey();
2.1.2. Циклы по условию
Циклы по условию необходимо организовывать, когда количество повторений цикла неизвестно и в ряде случаев является искомой величиной при решении задачи. Средства языка C# для организации циклов по условию приведены в п. …….
Пример 2.8. Определить количество (n) членов арифметической прогрессии
,
сумма которых впервые превысит заданное число р.
На каждом шаге алгоритма нужно добавлять к сумме s очередной член m = a + i*h (s = s + m), i = 1, 2, …, но при этом перед каждым прибавлением очередного члена проверять условие s <= p. Как только в первый раз условие не будет выполнено, т.е. будет s > p, необходимо выйти из цикла.
Далее приводится программа для решения задачи при a = 2, h = 3, p = 41. В программе текущее значение номера члена суммы обозначено через n. Значение этой переменной, при котором впервые оказалась s > p, и будет результатом.
int s = 0, n = 0, m;
const int a = 2, h = 3, p = 41;
while (s <= p)
{
m = a + n * h;
s = s + m;
n = n + 1;
}
n = n – 1;//вычитается 1, прибавленная после последнего изменения суммы.
Console.WriteLine(“{0:d}”, n);
Console.ReadKey();
Второй вариант программы использует оператор цикла с проверкой условия после первого прохождения цикла.
int s = 0, n = 0, m;
const int a = 2, h = 3, p = 41;
do
{
m = a + n*h;
s = s + m;
n = n + 1;
}while(s <= p);
n = n – 1;
Console.WriteLine(“{0:d}”, n);
Console.ReadKey();
З а м е ч а н и е. Член суммы m можно было бы вычислять рекуррентно: m = m + h, задав до начала цикла m = a (в программу при этом нужно внести и некоторые другие изменения, которые рекомендуется выполнить самостоятельно).
Пример 2.9. Вычислить сумму при x = 0.5. Суммирование прекратить, когда очередной член суммы будет меньше заданного ε = 0.0001.
double x = 0.5;
const double eps = 0.0001;
double s = 0, a;
int n = 1;
do
{
a = Math.Cos(n*x)/n;
s = s + a;
n = n + 1;
}while(Math.Abs(a)> eps);
Console.WriteLine(“Сумма равна {0:f4}”, s);
Console.ReadKey();
Пример 2.10. Методом итераций найти корень уравнения на отрезке [-1, 0.3] с точностью ε = 0.0001, принимая за начальное приближение x0 = -0.4 и вычисляя последовательно , i = 1, 2, 3, …, пока не будет выполнено условие .
При программной реализации метода итераций нет необходимости в использовании переменных с индексами. Для организации вычислительного процесса необходимо одновременно иметь в памяти значения лишь двух последовательных приближений (обозначим их х0 и х1). Следующее приближение х1 получается из предыдущего х0. Если условие достижения точности аbs(х1–х0)£ не выполняется, то следует переслать значение х1 в переменную х0 (х0=х1) и получить в х1 следующее приближение.
При организации цикла проверку условия удобно осуществлять после первого прохождения цикла, т.е. использовать цикл do … while.
double x0 = -0.4;
const double eps = 0.0001;
double x1, d;
do
{
x1 = 0.5 * (Math.Sin(x0 * x0) – 1);
d = Math.Abs(x1 – x0);
x0 = x1;
}while(d >= eps);
Console.WriteLine(“Корень равен {0:f4}”, x1);
Console.ReadKey();
Пример 2.11. Вычислить частное p и остаток q от деления двух натуральных чисел r и t, не используя операцию деления. Число r можно представить в виде . Будем последовательно вычитать t из r и подсчитывать количество вычитаний в переменной p. Значение q — результат последнего вычитания, когда в первый раз будет выполнено условие .
int r, t, q, p = 0;
r = 26;
t = 8;
q = r;
while (q >= t)
{
q = q – t;
p = p + 1;
}
Console.WriteLine(“Частное {0:d} Остаток {1:d}”, p, q);
Console.ReadKey();
Здесь используется цикл с проверкой условия до первого выполнения тела цикла (что важно), так как возможен случай, когда r < t, и тело цикла не должно выполняться ни разу.
Пример2.12. Корабль должен преодолеть путь в 3000 км. В первый день он прошел 200 км. Каждый следующий день он будет проделывать путь на 5% больше, чем в предыдущий день. Через какое время он прибудет в порт назначения?
Обозначим путь одного дня через Р. Вначале Р = 200. Путь следующего дня вычисляется как Р = Р + 0.05Р = 1.05Р. Это значение прибавляем к суммарному пути S: S = S + P. Количество дней обозначим через n и будем увеличивать его каждый раз на 1.
double s = 0.0, p = 200.0;
int n = 0;
while(s < 3000)
{
s = s + p;
n = n + 1;
p = p * 1.05;
}
Console.WriteLine(“{0:d}”, n);
Console.ReadKey();
2.1.3. Вложенные циклы.
Пример 2.13. Вычислить сумму при x, изменяющемся в пределах от 0.1 до 1 с шагом 0.05.
Вначале ограничимся вычислением суммы при заданном значении х. Здесь член суммы необходимо вычислять рекуррентно. Для вывода рекуррентной формулы выпишем выражения для двух последовательных членов суммы, например (i–1)-го и i-го, и, разделив i-ый член на (i–1)-ый, получим выражение, на которое необходимо домножить (i-1)-й член для получения i-го. Итак,
Таким образом, чтобы получить следующий i-й член из предыдущего (i-1)-го члена, его нужно домножить на 2*х/i.
Вычисление суммы для фиксированного значения х может быть осуществлено следующим образом:
double s, a, x = 0.1;
s = 1; a = 1;
for (int i = 1; i <= 12; i++)
{
a = a * 2 * x / i;
s = s + a;
}
Console.WriteLine(“{0:f4} {1:f4}”, x, s);
Эта последовательность операторов должна быть выполнена в цикле по x.
double s, a, x;
double xh = 0.1, xk = 1.0001, h = 0.05;
int n = (int)((xk – xh) / h + 1);
x = xh;
for (int j = 1; j <= n; j++)
{
s = 1; a = 1;
for (int i = 1; i <= 12; i++)
{
a = a * 2 * x / i;
s = s + a;
}
Console.WriteLine(“{0:f4} {1:f4}”, x, s);
x = x + h;
}
Console.ReadKey();
Такая структура программы, когда цикл выполняется внутри другого цикла, называется вложенными циклами.Далее приводится результат выполнения программы.
Замечание. Здесь в операторе вывода строка формата содержит пробелы, что и обеспечивает разделение при выводе столбцов значений x и s.
Пример 2.14. Вычислить сумму
для значений х, изменяющихся в пределах от 0.2 до 1 с шагом 0.2. Суммирование прекращать, когда очередной член суммы по абсолютной величине станет меньше e = 0.0001.
Задача сводится к организации вложенных циклов. Внешний цикл по счетчику обеспечивает изменение х (см. Пример 2.13). Во внутреннем цикле по условию осуществляется вычисление суммы (см. Пример 2.9).
Член суммы ai имеет более сложный вид, чем в примере 2.9. Его целесообразно представить в виде двух сомножителей:
ai = ci(2i – 1), где
будем вычислять по рекуррентной формуле, выражая последующий член через предыдущий:
Число значений х на отрезке от 0.2 до 1 с шагом 0.2 равно 5. В программе для контроля при каждом значении х вычисляется также функция , которая приближенно может быть представлена в виде указанной суммы.
const double xh = 0.2, h = 0.2, eps = 0.0001;
double a, x, s, y, c;
int n = 5, i;
x = xh;
for (int j = 1; j <= n; j++)
{
s = 1; c = -1; i = 1;
do
{
c = -c * x * x / ((2 * i – 1) * 2 * i);
a = c * (2 * i – 1);
s = s + a;
i = i + 1;
} while (Math.Abs(a) >= eps);
y = Math.Cos(x) + x * Math.Sin(x);
Console.WriteLine(“x= {0:f4} s= {1:f4} y= {2:f4}”, x, s, y);
x = x + h;
}
Console. ReadKey();
Вопросы для самопроверки
1. Что такое цикл? Операторы цикла for, while, do … while. Различия между ними.
2. Какие данные необходимы для организации цикла for? Что такое управляющая переменная цикла?
3. Циклы по условию и их организация.
4. Операторы break и continue. В каких случаях они используются?
5. Типовые алгоритмы циклической структуры: вычисление суммы n слагаемых, вычисление произведения n сомножителей, вычисление факториала, табулирование функции.
6. Вычисление суммы с использованием рекуррентных соотношений.
7. Вложенные циклы.
8. Согласование (приведение) типов.
9. Вывод с использованием формата.
Источник