Программирование переходов и циклов

Раньше (гл. 2, п. 2.3) было дано исчерпывающее объяснение тому, что представляют собой переходы в программах и как они выполняются на уровне машинного языка. Практически все алгоритмические языки, в том числе и Turbo Pascal 7.0, содержат средства, реализующие переходы.

В качестве оператора безусловного перехода в языке используется оператор Goto <метка>. Он означает, что от места в программе, где записан этот оператор, необходимо перейти к ее предложению, помеченному меткой. Имя метки может выбираться произвольно, однако начинаться с буквы и быть по возможности короче, например Goto ml.

Среди ярых идеологов структурного программирования существует мнение о том, что использование оператора безусловного перехода нежелательно, так как он запутывает программы, особенно в тех случаях, когда переходы осуществляются к начальным их участкам. Это действительно так, однако в практических случаях без этого оператора иногда трудно обойтись. Примеры использования оператора безусловного перехода будут рассмотрены позже.

Язык Turbo Pascal 7.0 располагает двумя операторами, с помощью которых программируются условные переходы. Один из них реализует выбор вычислений по одному из двух направлений, другой — по многим. Первый оператор записывается так:

If Условие

Then

Begin Операторы End

Else

Begin Операторы End;

Он действует следующим образом. Если условие, представленное логическим значением, истинно, осуществляется переход к выполнению операторов, следующих после словосочетания слов Then, Begin. Если же оно ложно, то осуществляется переход к выполнению операторов, следующих за словосочетанием Else, Begin.

Здесь операторы заключены в так называемые операторные скобки Begin, End. Такие операторы принято называть составными. Однако в тех случаях, когда оператор один, операторные скобки не употребляются. Кроме того, после первых операторных скобок точка с запятой не ставится, так как это не конец предложения, начинающегося словом If. Приведем примеры записи оператора условного перехода.

If a

Then

Begin

a:=Sin(x); y:=Cos(x) End

1) Else

Begin

b:=Sin(x); y:=Sqrt(x); End;

If (a10)

Then

2) a:=Exp (b)

Else

b:=Abs(c);

If (a=b) And (c=d)

Then

Begin

3) a:=c+d; b:=Vtf; End

Else

a:=b+c+d;

Кроме полного оператора условного перехода весьма часто применяется другой оператор, в котором часть предложения, начинающаяся словом Else, отсутствует. Он имеет такую форму.

If Условие

Then

Begin Операторы End;

Например,

If XoY

Then

Begin

Write ('Доступ запрещен');

Goto ml;

End;

Этот оператор называется усеченным оператором условного перехода и действует следующим образом. Если условие истинно, осуществляется переход к выполнению операторов, следующих за словосочетанием Then, Begin. Если оно ложно, переход не осуществляется, а продолжается выполнение инструкций программы, следующих за этим оператором. Таким образом, согласно указанному оператору происходит как бы вставка требуемого фрагмента программы, если условие истинно. Он лучше всего отображает смысл перехода на машинном языке: если условие выполняется — сделать переход, не выполняется — продолжить выполнения команд в естественном порядке. В этом операторе условного перехода также могут отсутствовать операторные скобки Begin, End. Кроме этого в приведенном примере продемонстрировано применение оператора безусловного перехода Goto m 1.

Оператор условного перехода может в обеих или в одной из ветвей содержать проверки некоторых логических условий. Говорят, что такие операторы вложены друг в друга. Для избежания ошибок вложенное условие лучше всего представлять как составной оператор. Например,

If Условие 1

Then

Begin

If Условие 2

Then

Begin Операторы End

Else

Begin Операторы End Else Операторы End;

Практика однако показывает, что такими инструкциями по возможности следует пользоваться реже, так как они часто оказываются довольно запутанными.

Оператор условного перехода, реализующий выбор вычислений по одному из многих направлений, часто называемый оператором выбора, имеет такую форму

Case Выражение of Список констант 1:

Begin

{Операторы}

End;

Список констант 2:

Begin

{Операторы}

End;

Список констант N:

Begin

{Операторы}

End;

Else

Begin

{Операторы}

End;

Он выполняется следующим образом. Сначала вычисляется значение выражения. Затем оно последовательно сравнивается с элементами списка констант 1, 2, ..., N. Если значение выражения равно одному из элементов списка, выполняются инструкции программы, записанные в операторных скобках Begin, End; этого списка. Если же значение выражения не совпадает ни с одним элементов списка 1, 2, ..., N, выполняются операторы, записанные в операторных скобках за словом Else.

Таким образом, принципиально оператор может осуществить переход в N+ точку программы. Для того чтобы его сконструировать, необходимо знать наперед возможные значения выражения и обеспечить несовпадение элементов списка констант. Иными словами, множества списков констант должны быть не-пересекающимися.

Синтаксис оператора Case допускает возможность опускать последовательность операторов, следующую за словом Else в том случае, если выбора по Else нет. Если значения выражения не совпадает ни с одним элементом списка констант 1, 2, N, выполняются инструкции программы, записанные за оператором Case без Else. Кроме того, при наличии одной инструкции, соответствующей тому или иному списку констант, операторные скобки Begin, End; можно не писать. Если константы представляют диапазон чисел, то вместо списка можно указать первую и последнюю константу диапазона. Например, список 1, 2, 3, 4, 5, 6, может быть заменен 1...6.

Рассмотрим следующий пример. Требуется составить программу, которая бы по заданному номеру месяца, вводимому с клавиатуры, выводила на экран название периода года.

Прежде всего заметим, что каждый период года определяется тремя месяцами: Лето — 6,7,8, Осень — 9,10,11, Зима — 12,1,2, Весна — 3,4,5. Поэтому программа может быть такой.

Program Time;

Uses

Crt; {Для возможности очистки экрана}

Labi?

ml; {Метка для повторного ввода номера месяца}

Var

n: Byte; {Номер месяца}

Begin

ml:

ClrScr;

Writeln ('Введите номер месяца'); Readln (n);

Writeln ('Номер мемяца n=', n);

Case n of

  • 6.. 8: Writeln ('Лето');
  • 9.. 11: Writeln ('Осень');
  • 12,1,2: Writeln ('Зима');
  • 3.. 5: Writeln ('Весна');

Else

Begin

Writeln (’Повторите ввод, он неверный'); Readln; {Для остановки до нажатия Enter} Goto ml;

End;

Writeln ('Программа завершена');

End.

В этой программе предусмотрена возможность повторения ввода, если номер месяца выбран ошибочно, т. е. он вне интервала [1, 12]. Для этого используются инструкции, записанные после слова Else в операторе Case, в том числе и инструкция безусловного перехода Goto ml. Попутно заметим, что после имени метки, к которой осуществляется переход, всегда ставится двоеточие. В списках констант указано по одному оператору вывода. Поэтому операторные скобки Begin, End там не используются. Наоборот, список инструкций, следующий за словами Else, взят в операторные скобки, так как инструкций больше одной — Writeln, Readln, Goto ml.

Безусловно, эта программа может быть составлена и без использования оператора выбора. Она, например, может быть такой (раздел объявлений опущен).

Begin

ml:

ClrScr;

Writeln ('Введите номер месяца');

Readln (n);

Writeln ('Номер месяца n=', n);

If (n12)

Then

Begin

Writeln ('Повторите ввод, он неверный');

Readln;

Goto ml;

End;

If (n > 6) And (n=<8)

Then

Writeln ('Лето');

If (n > 9) And (n=

Then

Writeln ('Осень');

If (n=12) Or (n=l) Or (n=2)

Then

Writeln ('Зима');

If (n > 3) And (n=<5)

Then

Writeln ('Весна');

End.

Как видим, в этой программе используются пять усеченных операторов If — Then. Она более громоздкая, чем предшествующая. Кроме того, основной недостаток этой программы состоит в том, что в случае, когда, например, выполняются условия лета, т. е. 6 < п < 8, остальные операторы If — Then будут проверяться, что требует дополнительного времени.

Теперь мы готовы к тому, чтобы составить программы решения задач по алгоритмам, изображенным на рис. 1.3—1.7, а также задач, которые будут сформулированы в процессе изложения материала. Для избежания путаницы программы будем называть номерами рисунков, на которых изображены алгоритмы.

В примере 1.1 (блок-схема алгоритма рис. 1.3) требуется по двум заданным действительным числам а, b найти сумму s, разность г, произведение р и частное п от деления а на Ь. Программа может быть такой:

Program Al.4; {А — алгоритм 1.4}

Var

a,b,s,r,p,h: real; {Исходные а, b и результаты вычислений}

Begin

Write ('Введите а, b ');

Readln (а, Ь);

s:=a+b; r:=a-b; p:=a*b;

Writeln ('Сумма s=', s:6:2);

Writeln ('Разность r =', r:6:2);

Writeln ('Произведение p =', p:6:2);

If b=0

Then

Writeln ('b=0, h - бесконечность');

Else

Begin

h:=a/b;

Writeln ('Частное h=', h:6:2);

End;

Writeln ('Программа завершена');

End.

В задаче 1.3 (блок-схема алгоритма рис. 1.5) требуется определить, какое из двух действительных чисел а, b больше или они равны. Программа, реализующая этот алгоритм, приведена ниже.

Program А1.6; {А — алгоритм 1.6}

Var

a,b,: real;

Begin

If a=b

Then

Writeln ('Числа равны');

Else

Begin

If a>;

Then

Writeln ('a>;

Else

Writeln ('a

End;

End;

Writeln (’Программа завершена');

End.

В задаче 1.4 (блок-схема алгоритма рис. 1.6) требуется вычислять значение ступенчатой функции Y. Простейшая программа в точности реализует алгоритм. Для этого в ней используются усеченные операторы условного перехода If — Then и оператор безусловного перехода Goto m.

Program А1.7; {А — алгоритм 1.7}

Lable

Finish;

Var

x,y,: real;

Begin If x=< 1 Then

Begin

Y:=l-x; Writeln ('Y=', Y:6:2); Goto Finish; End;

If x=<2

Then

Begin

Y:=l/x*x; Writeln ('Y=', Y:6:2); Goto Finish; End;

If x=<3

Then

Begin

Y:=Sqrt(l+x*x*x); Writeln (’Y=',Y:6:2); Goto Finish; End; Y:=l+x+x*x; Writeln (’Y=',Y:6:2);

Finish:

Writeln ('Программа завершена');

End.

В задаче 1.5 (блок-схема алгоритма рис. 1.7) необходимо составить программу вычисления корней квадратного уравнения с действительными коэффициентами. Простейшая программа, в точности отображающая алгоритм, как и предшествующая программа, использует усеченные операторы условного перехода If — Then и оператор безусловного перехода Goto М. Она приведена ниже.

Program Al.8; {А — алгоритм 1.8}

{Вычисление корней квадратного уравнения}

Labi?

Finish;

Var

a,b,с: real; {Коэффициенты уравнения} xl,x2: real; {Корни уравнения} d: real; {Дискриминант} h,k,г,g: real; {Вспомогательные переменные}

Begin

d:=b*b-4*a*c; h:=a+a; k:=-b/h;

If d<0

Then

Begin

g:=Sqrt (Abs(d)); r:=g/h;

Writeln (’Корни комплексные');

Writeln ('xl=', k:4:2, '+i', r:4:2);

Writeln ('x2=', k:4:2, ’-i’, r:4:2);

Goto Finish;

End;

If d>0 Then Begin

g:=Sqrt (d); r:=g/h;

Writeln (’Корни действительные');

Writeln ('xl=', (k+r):4:2);

Writeln 0x2=, (к-г):4:2);

Goto Finish;

End;

Writeln ('Корни равные');

Writeln ('х1=', к:4:2);

Finish:

Writeln ('Программа завершена');

End.

Желание отказаться от применения оператора безусловного перехода Goto М, т. е. строго следовать принципам структурного программирования, приводит к программе со вложенными операторами If — Then, фрагмент которой приведен ниже.

If d<0

Then

Begin

g:=Sqrt (Abs(d)); r:=g/h;

Writeln ('Корни комплексные');

Writeln ('xl=', k:4:2, '+i', r:4:2);

Writeln ('x2=', k:4:2, '-i', r:4:2);

End;

Else

If d>0

Then

Begin

g:=Sqrt (d); r:=g/h;

Writeln ('Корни действительные');

Writeln ('xl=', (k+r):4:2);

Writeln ('x2=', (k-r):4:2);

End;

Else

Begin

Writeln ('Корни равные');

Writeln ('xl=', k:4:2);

End;

End;

End.

Для программирования циклов, т. е. повторяющихся участков программы (гл. 1, п. 4.1), в языке Turbo Pascal предусмотрены три оператора: арифметический For-do, а также итерационные циклы While-do и Repeat-Until. Арифметический оператор цикла полностью записывается так:

For i=n 1 to n2 do

Begin

{Инструкции тела цикла}

End;

и читается следующим образом: для i, равного n 1, до i, равного п2, изменяющегося с шагом единица, выполнять инструкции тела цикла.

Таким образом, в этом операторе переменная i (параметр

цикла) играет роль счетчика циклов. В соответствии с этим вы-

гт1

полнится —-— + 1 повторений (итераций) тела цикла. Цикл не

повторяется ни один раз, если nl > п2.

Записанный арифметический оператор цикла действует следующим образом. Сначала проверяется условие nl п2, тело цикла пропускается и выполняются инструкции программы, следующие за телом цикла. В противном случае, т. е. когда nl < п2 истинно, подсчитывается количество итераций и согласно полученному их значению выполняется соответствующее число повторений тела цикла. Имеется другая форма записи арифметического цикла:

For i=n2 downto nl do

Begin

{Инструкции тела цикла}

End;

Согласно этой форме параметр цикла i с шагом единица изменяется от большего значения п2 к меньшему nl. Число повто-

рении тела цикла определяется по выражению —-— + 1. Цикл

не выполняется ни один раз, если n2 < n 1, т. е. в этом случае тело цикла пропускается.

В обеих формах записи арифметического цикла операторные скобки Begin, End могут отсутствовать при условии, что в теле

цикла используется одна инструкция. Рассмотрим примеры применения арифметического цикла на задачах, изложенных в гл. 1, п. 4.1.

В задаче 1.6 (алгоритм рис. 1.8) требуется найти сумму п чисел. В соответствии с алгоритмом сначала требуется ввести в ОП компьютера числа хх, ..., хп, а затем их суммировать. Для этого пришлось бы определить одномерный массив для хранения п чисел, а затем в цикле читать очередное число и прибавлять его к накопленной сумме. Поскольку программирование обработки массивов еще не рассматривалось, мы отступим от такого порядка действий и будем вводить каждое очередное число с клавиатуры в цикле.

Предварительно заметим, что любой цикл может быть запрограммирован уже известными нам средствами: с помощью оператора условного и безусловного переходов. Для сравнения две программы приведены одна за другой.

Program Al.9; {А — алгоритм 1.9}

Labi?

ml ;

Var

n,i: integer; {Количество чисел и счетчик циклов}

x,S,: real; {Очередное число и сумма}

Begin

Writeln ('Введите количество чисел n); Readln (п);

Writeln ('Введите первое число х'); Readln (х);

S:=x;

i:=2;

ml:

If i>n

Then

Writeln ('Сумма чисел S=', S:6:2);

Else

Begin

Writeln ('Введите очередное число x');

Readln (x);

S:=S+x;

i:=i+l; Goto ml;

End;

Program AI.9b; {A — алгоритм 1.9}

Var

n,i: integer; x,S,: real;

Begin

Writeln ('Введите количество чисел n'); Readln (n);

Writeln ('Введите первое число x'); Readln (x);

S:=x;

For i=2 to n do Begin

Writeln ('Введите очередное число х'); Readln (х); S:=S+x;

End;

End.

Как видим, программа с применением цикла For — do существенно короче и изящнее.

Программа вычисления функции п (блок-схема алгоритма рис. 1.9) имеет такой вид:

Program А 1.10; {А — алгоритм 1.10}

Var

n: integer; {Очередное число в произведении п!=1 • 2 •... • п}

F: longint; {Значение функции п!}

Begin

Writeln ('Ввести п < 9'); Readln (п);

F:=l;

For i=2 to n do Begin

F:=F*i;

Writeln ('F=', F: 10, 'n=', n:2);

End;

End.

В этой программе введено ограничение на число п.

Оно должно быть меньше 9, так как 10! > 3 • 106 и объявление longint не обеспечит размещение его в памяти компьютера. Для того чтобы вычислять значения п для п > 10, необходимо У7 объявить как вещественное, например real, а формат вывода определить как число с плавающей точкой.

Теперь, когда мы познакомились с тем, как используется арифметический цикл For — do, не представляет труда, следуя алгоритмам решения задач 1.8—1.10 (блок-схемы рис. 1.10—1.12),

составить программы реализации этих алгоритмов. Поэтому оставляем программирование указанных задач в качестве самостоятельных заданий.

Составим программу реализации алгоритма, решающего задачу 1.11 (блок-схема рис. 1.13). Этот алгоритм заставляет пользователя ввести правильные исходные данные п, т числа сочетаний с;.

Program Al. 14; {Вычисление числа сочетаний С"'}

Uses

Crt; {Для очистки экрана}

Labi?

ml; {Метка}

Var

n,m: integer; {Исходные числа в С"’}

С: longint; {Число сочетаний С"'}

Begin

ml:

ClrScr;

Writeln (’Введите количество чисел n,m’); Readln (n,m);

If n

Then

Begin

Writeln (’Повторите ввод’); Readln;

Goto ml;

End;

If m=l

Then

Writeln ( C=’, n: 10);

End;

If m=n

Then

Writeln (’С=Г);

End;

C:=n;

For i=l to m-1 do Begin

C:=(n-i)*C/(i+l);

End;

Writeln (’C= C);

Writeln (’Программа завершена’);

Эта программа работает следующим образом. Вначале очищается экран и выводятся значения п, т. Если п < т, выводится сообщение «Повторите ввод», которое не исчезнет до нажатия клавиши Enter. После этого снова очищается экран и требуется ввести числа п, т.

В задаче 1.12 (блок-схемы алгоритмов рис. 1.14, 1.15) требуется вычислить значение полинома Рп(х) степени п для некоторого действительного х Программа, реализующая алгоритм вычисления значения Рп(х) по схеме Горнера, приведена ниже.

Program Al. 16; {Вычисление полинома Р„(х) по схеме Горнера}

Var

n: integer; {Показатель степени х} х: real; {Значение основания х в степени х"} a: real; {Коэффициент при степени хЛ}

р: real; {Значение полинома}

Begin

Writeln ('Введите х, n'); Readln (х,п);

р:=0;

For i=n downto 0 do

Begin

Writeln ('Введите очередное a='); Readln (a); p:=p*x+a;

End;

Writeln ('p=', p:8:2);

Writeln ('Программа завершена');

End.

В этой программе используется арифметический цикл, в котором переменная / убывает от n до 0. При этом предполагается, что коэффициенты полинома вводятся в таком порядке

^7!’ ®П-1’ •••5 ?0-

К сожалению, в арифметических циклах языка Turbo Pascal 7.0 не предусмотрено изменение шага управляющей переменной /' больше, чем на единицу, как это делается в Fortran, Basik, С.

В связи с этим возникают неудобства, что заставляет прибегать к использованию в теле цикла дополнительных операций.

Рассмотрим, например, простейшую задачу суммирования четных или нечетных элементов некоторого их ряда. Поскольку шаг изменения управляющей переменной /' = 1, для каждого очередного числа необходимо проверять, четен его индекс или нет.

Для этого можно воспользоваться тем, что остаток от деления четных чисел нацело всегда равен нулю. Поэтому фрагмент программы может быть таким:

S:=x;

For i=2 to n do

Begin

Writeln ('Введите очередное число x'); Readln (x);

j:=i mod 2 If j=0 Then

S:=S+x;

End;

Для суммирования нечетных элементов ряда цикл следует начать с / = 1, а оператор проверки условия конструировать так: If j<>0.

В общем же в тех случаях, когда в циклах необходимо оперировать с шагом / > 2, лучше всего использовать циклы итерационного типа.

Раньше мы говорили о том, что различают итерационные циклы с предусловием и постусловием. Блок-схемы этих циклов приведены соответственно на рис. 4.4, 4.5.

Блок-схема цикла с пред- Рис. 4.5. Блок-схема цикла с постусловием условием

Рис. 4.4. Блок-схема цикла с пред- Рис. 4.5. Блок-схема цикла с постусловием условием

В циклах с предусловием перед выполнением операторов тела цикла сначала проверяется условие. Если оно истинно и до тех пор пока оно истинно, повторяется выполнение операторов тела цикла.

В циклах с постусловием сначала выполняются операторы тела цикла, а затем проверяется условие. Если же оно ложно и до тех пор, пока оно ложно, повторение продолжается.

Таким образом, в циклах с предусловием тело цикла может никогда не быть выполнено. В циклах с постусловием оно выполняется, по крайней мере, один раз.

Для того чтобы прекратить повторение вычислений, в теле цикла обоих типов должен присутствовать оператор, который с каждым витком ослабляет (релаксирует) условие.

Итерационные циклы с предусловием и постусловием имеют такие формы записи:

While Условие do Repeat

Begin {Тело цикла}

{Тело цикла} Until Условие;

End;

Первая запись читается так: пока условие истинно, выполнять тело цикла, вторая — так: выполнять тело цикла до тех пор, пока условие ложно.

Рассмотрим примеры составления программ с использованием итерационных циклов. В задаче 1.13 (блок-схема алгоритма рис. 1.17) рассматривается задача табулирования функции /(х) на интервале [a, b, а < b с шагом Ах. Для ее решения предложено два алгоритма: с использованием арифметического и итерационного циклов с предусловием. В приведенной ниже программе применяется итерационный цикл. В качестве функции рассматривается у = sin(2x) • cos(x).

Program Al. 18; {Табуляция функции, алгоритм 1.18}

Var

х: real; {Аргумент функции}

a,b: real; {Левая и правая границы интервала}

dx: real; {Шаг изменения х}

у: real; {Значение функции}

Begin

Writeln ('Введите a,b,dx'); Readln (a,b,dx,); x:=a;

While x

y:=Sin(2*x)*Cos(x);

Writeln ('x=', x:6:2, 'y=', y:6:2);

x:=x+dx;

End;

x:=x-dx;

If x=b

Then

Begin

y:=Sin(2*b)*Cos(b);

Writeln ('x=', x:6:2, 'y=', y:6:2);

End;

End.

В этой программе оператором тела цикла, ослабляющим условие х<Ь (увеличивается х), является оператор присваивания x:=x+dx.

В задаче 1.14 (блок-схема алгоритма рис. 1.18) рассматривается проблема построения алгоритма поиска наибольшего общего делителя НОД двух целых чисел а, b и наименьшего целого кратного этих чисел. Программа, реализующая алгоритм Евклида с использованием итерационного цикла, приведена ниже.

Program А1.19; {Поиск НОД и НОК, алгоритм 1.19}

Var

a,b: integer; {Исходные числа}

NOD: integer; {Наибольший общий делитель}

NOK: integer; {Наименьшее общее кратное} x,u,v: integer; {Вспомогательные переменные}

Begin

Writeln ('Введите a,b,'); Readln (a,b); u:=a; v:=b;

While xob do

Begin

If a>

Then

Begin

x:=a-b; a:=x;

End;

Else

Begin

x:=a; a:=b; b:=x;

End;

End;

NOD:=a; NOK:=u*v/NOD;

Writeln ('a=', a:6, 'b=', b:6, 'NOD=', NOD:6);

Write ('NOK=', N0K:6);

Writeln ('Программа завершена');

End.

В этой программе контроль за изменением количества повторений в цикле While do осуществляется изменением переменных в операторах а:=х и Ь:=х.

Программа, реализующая алгоритм вычисления значения цепной дроби (задача 1.15, блок-схема алгоритма рис. 1.19), такая.

Program Al.20; {Вычисление значения цепной дроби, алгоритм 1.20}

Var

х,у: real; {Переменная цепной дроби и ее значение} a,b,c: real; {Вспомогательные переменные } i: integer; {Количество уровней цепной дроби }

Begin

Writeln ('Введите х',); Readln (х); а:=х*х; b:=256; c:=a+b/a; i=7;

While i< 1 do

Begin

b:=0.5*b; c:=a+b/a; i:=i-l;

End;

Writeln ('y=', x/c:6:2, 'x', x:6:2);

Writeln ('Программа завершена');

End.

Контроль за количеством повторений тела цикла в этой про-граме осуществляется оператором i:=i-l.

Теперь рассмотрим пример составления программы с использованием итерационного цикла Repeat-Until. Он взят из книги [35].

Для последовательности действительных чисел, заканчивающейся нулем и не содержащей больше нулевых элементов, определить, содержит ли эта последовательность хотя бы два равных соседних элемента.

Очевидно, что сформулированная задача решается циклическим сравнением пар соседних элементов. Как только встречаются два равных элемента, осуществляется выход из цикла и вывод на экран значений элементов и их места в ряду. В противном случае сообщается, что таких элементов нет.

Исходные данные: х1, х2 — очередное и следующее число в ряду; [ — место очередного числа в последовательности чисел. Алгоритм решения задачи включает следующие действия: Шаг 1. Ввести х,, х2.

Шаг 2. Положить /= 1.

Шаг 3. Если х, =х2, перейти к шагу 8.

Шаг 4. Положить х, = х2, / = / + 1.

Шаг 5. Ввести очередное х2.

Шаг 6. Если х2 ф 0, вернуться к шагу 3.

Шаг 7. Вывести «Равных чисел нет» и перейти к шагу 9.

Шаг 8. Вывести «Равные числа х( и х/+1».

Шаг 9. Остановиться.

Блок-схема алгоритма приведена на рис. 4.6.

Программа, реализующая алгоритм, имеет такой вид:

Program A4.5; {Алгоритм 4.6}

Labi?

Finish;

Var

xl,x2: real; {Два очередных числа ряда} i: integer; {Номер числа в ряду}

Begin

Writeln ('Введите xl,x2',); Readln (xl,x2);

i:=l;

Repeat

If xl=x2 Then

Begin

Writeln ('Номера чисел', i:3, (i+l):3);

Goto Finish;

End

Else

Begin

xl:=x2; i:=i+l;

Writeln ('Введите очередное число x2'); Readln (x2);

End;

Until

x2=0;

Writeln ('Равных чисел нет');

Finish:

Writeln ('Программа завершена');

End.

Алгоритм поиска двух равных чисел в ряду

Рис. 4.6. Алгоритм поиска двух равных чисел в ряду

Использование оператора цикла Repeat-Until в этой программе обусловлено тем, что сначала необходимо сравнить два первых числа, а затем в зависимости от результата выйти из цикла или продолжить его. Здесь необходимо сказать, что выйти досрочно из цикла всегда можно. Для этого есть и специальный оператор Break (прервать). Однако войти в цикл, минуя его начало, нельзя.

Есть также оператор Continue (продолжать), с помощью которого можно возвратиться к началу повторений, не закончив выполнять все оставшиеся после Continue операторы тела цикла. Особенность же оператора Break состоит в том, что он, выполняя выход из цикла, осуществляет переход к участку программы, следующему сразу же за инструкциями цикла, в то время как во многих программах этого не требуется (см. пример выше).

Покажем, как применяются операторы Break и Continue. Для этого рассмотрим следующую задачу. Вывести на экран дисплея последовательность прописных букв латинского алфавита, прервав вывод на букве Р.

Согласно кодовой таблице прописные буквы латинского алфавита имеют десятичные коды, изменяющиеся от 65 до 90. Поэтому в этих пределах следует организовать повторение вывода символа согласно его коду. При этом вспомним, что преобразование кода в символ осуществляет функция Chr (код). Буквы будем выводить в строку.

Программа с применением оператора For-do имеет такой вид:

Program Sim; {Вывод символов на экран}

Begin

For i=65 to 90 do

If Chr(i)= ’P’ Then Break Else

Write (Chr(i));

Writeln ('Программа завершена');

End.

Согласно представленной программе вывод букв будет продолжаться до тех пор, пока не встретится буква Р. Далее произойдет выход из цикла и переход к выводу «Программа завершена».

Рассмотрим решение этой задачи с применением оператора Repeat-Until. Выведем все буквы, исключая Р. Приведем только фрагмент программы.

Begin

i:=65;

Repeat

Begin

If Chr(i)='P' Then i:=i+l; Continue;

End

Begin

Else Write (Chr(i)); i:=i+l;

End;

Until i>65;

Writeln ('Программа завершена');

End.

Программа выполняется следующим образом. До тех пор пока в цикле не встретится буква Р, выводятся все предшествующие буквы. Когда же это произойдет, осуществляется переход к началу тела цикла и далее продолжается вывод всех остальных букв, кроме Р.

Приведем пример использования оператора цикла While-do для вычисления числа я с заданной точностью s.

Известно, что величина я/4 приближается знакопеременным рядом я/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 + ... . Точность вычисления считается достигнутой, если очередной член ряда 1/(2 • п - 1) станет меньше или равен s. Таким образом, будем накапливать сумму членов ряда Р до тех пор, пока е= 1/(2п- 1)>е. Начальное значение суммы Р = 1. Знак очередного члена ряда будем определять умножая его на 1 или -1. Алгоритм решения задачи приведен ниже. Его блок-схема изображена на рис. 4.7.

Шаг 1. Ввести е.

Шаг 2. Положить Р- 1, е = Р, /7 = 2, а = -1.

Шаг 3. Если е< s, перейти к шагу 6.

Шаг 4. Вычислить е = /(2п - 1), Р = Р + а ? е.

Шаг 5. Положить п = п+ ,а = -аи вернуться к шагу 3.

Начало

_у_

/ Ввести

/ 8

I

Р = 1,е=Р, п = 2,а=

Да

Нет

е = 17(2/7-1)

Р= Р+ а-е

п = п+,а = -а

г~

/Вывести п = 4 Р, є

V

Конец

Рис. 4.7. Алгоритм вычисления числа л с точностью є

Шаг 6. Вывести я = 4 • Р, е.

Шаг 7. Остановиться.

По алгоритму составим программу.

Program Pi; {Вычисление числа п с заданной точностью}

Var

n: integer; {Номер члена ряда}

Р: real; {Текущая сумма ряда} е: real; {Значение элемента ряда}

Eps: real; {Точность вычисления} a: integer;

Begin

Write ('Введите Eps',); Readln (Eps);

P:=l; e:=P; n:=2; a:=-l;

While e>Eps do Begin

e:=l/(2n-l);

P:=P+a*e;

n:=n+l;

a:=-a;

End;

Writeln ('Значение я =', 4*P:6:2, 'Eps=', Eps:6:2);

End.

Программа выполняется следующим образом. После ввода Eps, например 0,001, и присваивания начальных значений Р= 1, е= Р, п = 2, а = -1 проверяется условие е< Eps, если оно истинно, а это так потому что, е= Р> Eps = 0,001, выполняются операторы тела, изменяющие, в частности, номер элемента ряда (п:=п+1) и знак а (а:=-а). После этого проверка условия е > Eps повторяется. Эти повторения продолжаются до тех пор, пока за счет последовательного уменьшения величины е выполнится неравенство е < Eps.

 
< Пред   СОДЕРЖАНИЕ     След >