Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КОНСПЕКТ 2.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
241.66 Кб
Скачать

Оператор цикла for

Вновь вернемся к рассмотренным выше примерам, но теперь решим соответствующие задачи при помощи операторов цикла. Суммирование чисел от N1 до N2 легко выполнить при помощи следующей программ С++, использующей оператор цикла for:

С++

sum=0;

for(x=N1;x<=N2;x++)

sum+=x;

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

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

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

Например, будем вычислять одновременно сумму всех целых чисел от N1 до N2 и сумму квадратов этих же чисел. Это можно сделать при помощи следующей программы:

С++

sum1=0;

sum2=0;

for(x=N1;x<=N2;x++)

{

sum1+=x;

sum2+=x*x;

}

Точка с запятой после закрывающей скобки } в программе на С не ставится.

Главным предназначением оператора цикла for является работа с целочисленными переменными или, более широко, с дискретными типами данных. Более подробно к этому вопросу мы еще вернемся, а пока что отметим, что на языке С, в принципе, допускается использование оператора for и с вещественными типами данных. Однако это не рекомендуется, поскольку для действий с вещественными числами существуют другие, более подходящие, операторы цикла.

Оператор цикла с постусловием

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

С++

sum=1;

y=x;

do{

sum+=y;

y*=x;

}while(fabs(y)>=1e-17);

Обратим внимание на то, что в цикле С++ проверяют условие продолжения цикла.

В программе на С++ все операторы, расположенные между служебными словами do и while дополнительно берутся в операторные скобки {}.

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

Оператор цикла с предусловием

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

С++

Sum=1;

y=x;

while(fabs(y)>=1e-17)

{

sum+=y;

y*=x;

};

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

Суммирование степенных рядов

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

Пример 1. Экспонента. Функция , где е2,71828182845905 вычисляется следующим образом:

Здесь 2!=12, 3!=123, 4!=1234,… При суммировании подобного ряда главное, как и в предыдущем случае, наилучшая организация вычисления очередного члена ряда. Хуже всего было бы вычислять для каждого члена ряда отдельно числитель, т.е. соответствующую степень х, и отдельно знаменатель, т.е. соответствующее произведение. Мы поступим следующим образом. Обозначим общий член ряда:

Тогда справедливо соотношение:

Действительно:

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

.

Теперь мы можем написать следующую программу на С++:

y=1;

k=1;

a=1;

do

{

a=a*x/k;

y=y+a;

k=k+1;

}

while (fabs(a)>=abs(y)*1e-20);

Эта программа вычисляет значение функции у= для одного заданного значения х. Вначале переменные у, k и а получают свои начальные значения (инициализируются). Затем, при каждом проходе цикла, вычисляется очередной член ряда а, его значение прибавляется к величине у, накапливая таким образом сумму ряда; затем вычисляется номер следующего члена ряда k и цикл повторяется. Вычисления прекращаются после достижения относительной погрешности:

/

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

Пример 2. Однако, не всегда результаты вычислений бывают настолько очевидными. Рассмотрим, например, ряд, при помощи которого вычисляется функция sin x:

Обозначая через k=0, 1,… номер члена ряда можем записать рекуррентную зависимость для общего члена ряда:

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

y:=x; a:=x; k:=1;

repeat

a:=-a*x*x/2/k/(2*k+1);

y:=y+a;

k:=k+1;

until abs(a)<=abs(y)*1e-20;

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

На рисунке представлен график функции y=sin x, построенный на основе нашей программы.

Мы видим, что на протяжении нескольких периодов график имеет привычную форму, но затем приобретает хаотический вид. Рассмотрим причины этого явления. Дело в том, что в данном случае суммируемый ряд является знакопеременным. Соседние члены ряда имеют противоположные знаки. В итоге суммирование ряда фактически сводится к последовательности вычитаний. При достаточно больших значениях аргумента х (напомним, что х берется в радианах) происходит вначале значительное увеличение общего члена ряда, а только затем его уменьшение. В итоге значение функции sin x, которое не бывает больше единицы, получается за счет вычитаний чисел, значительно больших единицы. При этом теряются старшие разряды и резко возрастает погрешность вычислений. С ростом х эта погрешность становится настолько большой, что превосходит результаты вычислений. Это и приводит к хаотическому поведению графика, поскольку просуммированный ряд может дать любые, заведомо неверные, результаты.

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