Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР7-С++-05 апреля-2012.doc
Скачиваний:
19
Добавлен:
15.09.2019
Размер:
2.45 Mб
Скачать

1.11. Правила организации циклических алгоритмов

Циклические алгоритмы разделяются на две группы:

Арифметический цикл (управляемый счетчиком). Как правило, повторяется заранее известное число раз. Например, спортсмен должен пробежать 10 кругов или 40 км.

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

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

При выполнении цикла всегда должны быть пройдены следующие этапы.

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

Точка входа в цикл: момент передачи управления первому оператору тела цикла.

Итерация: очередное выполнение тела цикла, то есть фрагмента, который должен быть повторен многократно. Как правило, включает в себя изменение параметра цикла.

Точка проверки условия: момент проверки условия, при котором решается, делать ли новую итерацию, или перейти к оператору, стоящему за циклом. Как правило, в проверке условия явно или нет, присутствует параметр цикла.

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

Не всегда эти составляющие присутствуют явным образом.

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

1. while…do:

// подготовка цикла

while (условие)

{ // количество повторений любое

// тело цикла

}

2. do…while:

// подготовка цикла

do

{ // количество повторений любое

// тело цикла

}

while (условие);

3. for:

for (// объявление параметра цикла)

{ // количество повторений фиксировано

//тело цикла

}

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

При проектировании цикла необходимо решать две задачи:

1. Разработка потока управления. Здесь наиболее важный шаг, это выбор параметра цикла. Для параметра цикла должно быть известно:

каково условие завершения цикла,

каково начальное значение параметра,

как обновляется параметр цикла.

2. Планирование действий внутри цикла. Здесь важно решить, что представляет собой отдельная итерация, и точно определить:

как инициализируется повторяющийся процесс,

какие действия в него входят,

как он обновляется.

Пример 7.46

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

Условие задачи: снаряд выпущен под углом λ к горизонту со скоростью V (рис. 1.5). Требуется определить высоту и дальность полета в течение промежутка времени от t = 1 сек. до t = 10 сек с интервалом, равным 1 сек.

Определяем изменение параметра цикла и условие выхода. Содержанием тела цикла является вычисление очередного значения и вывод на печать. Число повторений заранее известно, и равно 10-ти, значит, цикл арифметического типа.

Арифметический цикл можно организовать, используя любой из операторов цикла С, что и показано в полном тексте программы.

#include <stdio.h>

#include <math.h>

#define G 9.8 // константа тяготения

void main(void)

{

// переменные, которые являются начальными значениями

float V; // скорость

int A_Grad; // угол в градусах

// переменные, участвующие в вычислениях

float Alpha; // угол

float t; // время полета

float Sy, Sx; // высота и дальность

printf ("Введите скорость и угол в градусах\n");

scanf ("%f%d", &V, &A_Grad);

Alpha = (float) A_Grad * M_PI/360.;

// арифметический цикл. Управляющая переменная t = [1.0; 10.0], Δt= 1

// 1. Оператор for.

printf ("--------------------------------------\n");

printf ("--Время--Высота--Дальность\n"); // подготовка цикла

printf ("--------------------------------------\n");

for (t = 1.;t <= 10.; t += 1.)

{

Sx = V*t*cos (Alpha);

Sy = V*t*sin (Alpha) – 0.5*G*t*t;

printf ("%6.2f %6.2f %6.2f\n", t, Sy, Sx);

}

// 2. Оператор while.

printf ("--------------------------------------\n");

printf ("--Время--Высота--Дальность\n"); // в подготовке цикла

printf ("--------------------------------------\n"); // основное t = 1

t = 1.;

while (t <= 10.)

{

Sx = V*t*cos (Alpha);

Sy = V*t*sin (Alpha) – 0.5*G*t*t;

printf ("%6.2f %6.2f %6.2f\n", t, Sy, Sx);

t+=1.;

}

// 3. Оператор do.

printf ("--------------------------------------\n");

printf ("--Время--Высота--Дальность\n");

printf ("--------------------------------------\n"); // подготовка цикла

t = 1.;

do

{

Sx = V*t*cos (Alpha);

Sy = V*t*sin (Alpha) – 0.5*G*t*t;

printf ("%6.2f %6.2f %6.2f\n", t, Sy, Sx);

t+=1.;

}

while (t <= 10.);

}

В этом примере алгоритм приведен в трех вариантах, чтобы показать отличия в организации циклических алгоритмов при использовании разных операторов цикла. Решение задачи выявляет одну ее особенность. Приведем одну из распечаток решения, полученную при скорости 100 м./сек. и угле, равном 30°.

--------------------------------------

--Время--Высота--Дальность

--------------------------------------

1.00 20.98 96.59

2.00 32.16 193.19

3.00 33.55 289.78

4.00 25.13 386.37

5.00 6.91 482.96

6.00 -21.11 579.56

7.00 -58.93 676.15

8.00 -106.54 772.74

9.00 -163.96 869.33

10.00 -231.18 965.93

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

Рис.1.5. Траектория полета

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

Итерационный цикл также можно организовать с использованием любого из операторов цикла.

Приведем не полный текст программы, а только основную его часть, отвечающую за организацию циклов. Условие завершения цикла V*t*sin Alpha) – 0.5*G*t*t > 0 управляет выполнением циклического алгоритма независимо от используемого оператора цикла посредством параметра цикла t, входящего в запись условия.

//1. Оператор for.

printf ("--------------------------------------\n");

printf ("--Время--Высота--Дальность\n");

printf ("--------------------------------------\n");

for (t = 1.;V*t*sin (Alpha) – 0.5*G*t*t > 0.; t += 1.)

{

Sx = V*t*cos (Alpha);

Sy = V*t*sin (Alpha) – 0.5*G*t*t;

printf ("%6.2f %6.2f %6.2f\n", t, Sy, Sx);

}

// 2. Оператор while.

printf ("--------------------------------------\n");

printf ("--Время--Высота--Дальность\n");

printf ("--------------------------------------\n");

t = 1.;

while (V*t*sin (Alpha) – 0.5*G*t*t > 0.)

{

Sx = V*t*cos (Alpha);

Sy = V*t*sin (Alpha) – 0.5*G*t*t;

printf ("%6.2f %6.2f %6.2f\n", t, Sy, Sx);

t += 1.;

}

// 3. Оператор do.

printf ("--------------------------------------\n");

printf ("--Время--Высота--Дальность\n");

printf ("--------------------------------------\n");

t = 1.;

do

{

Sx = V*t*cos (Alpha);

Sy = V*t*sin (Alpha) – 0.5*G*t*t;

printf ("%6.2f %6.2f %6.2f\n", t, Sy, Sx);

t += 1.;

}

while (V*t*sin (Alpha) – 0.5*G*t*t > 0.);

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

--------------------------------------

--Время--Высота--Дальность

--------------------------------------

1.00 20.98 96.59

2.00 32.16 193.19

3.00 33.55 289.78

4.00 25.13 386.37

5.00 6.91 482.96

Изменим постановку задачи, чтобы получить чисто итерационный процесс. Например, определить время полета и его дальность при заданных начальных значениях скорости и угла. В этой постановке задачи итоговыми значениями являются t и Sx, но для проверки условия завершения нужно вычислять значение вертикальной координаты. Переменная Sy не нужна, так как формула проверки условия записана в виде логического выражения. Вывод заголовка не входит в подготовку цикла, а вывод на печать вынесен за тело цикла.

//1. Оператор for.

for (t = 1.; V*t*sin (Alpha) – 0.5*G*t*t > 0.;t+=1.)

Sx = V*t*cos (Alpha);

printf ("--Время--Дальность\n");

printf ("%6.2f %6.2f \n", t, Sx);

// 2. Оператор while.

t = 1.;

while (V*t*sin (Alpha) – 0.5*G*t*t > 0.)

{

Sx = V*t*cos (Alpha);

t += 1.;

}

printf ("--Время--Дальность\n");

printf ("%6.2f %6.2f \n", t, Sx);

// 3. Оператор do.

t = 1.;

do

{

Sx = V*t*cos (Alpha);

t += 1.;

}

while (V*t*sin (Alpha) – 0.5*G*t*t > 0.);

printf ("--Время--Дальность\n");

printf ("%6.2f %6.2f \n",t,Sx);

Еще более интересной задачей является задача определения попадания в цель. Если известны координата цели и ее размер, то после выполнения цикла значение Sx можно сравнить с координатой цели, например, пусть координата центра мишени Sm, а ее линейный размер L, тогда условие попадания запишется:

if ( Sx < Sm + 0.5*L && Sx > Sm – 0.5*L)

printf ("Цель поражена\n");

else

if (Sx < Sm – 0.5*L)

printf ("Недолет\n");

else

printf ("Перелет\n");

Надо заметить, что и в последнем случае задача решена некорректно. Значение t выбрано дискретным, и изменение t равно 1 сек. Следовательно, точность вычисления неизвестна, но весьма невелика.

Еще более интересной задачей является задача подбора входных данных t и V таким образом, чтобы обеспечить попадание в цель. Это задача моделирования, имеющая более сложное решение.