Введение 8 Этапы создания Windowsприложения 8
Скачать 6.98 Mb.
|
6.2. Цикл с условиемЦикл с условием используется в тех случаях, когда число повторений цикла заранее неизвестно. Например, при обработке совокупности чисел, ввод которой прекращается при появлении первого нуля. Цикл с условием – это многострочный оператор Visual Basic 2005, первая строка которого начинается со слова Do, а последняя строка начинается со слова Loop. Выделяют две разновидности цикла с условием: цикл с предусловием и цикл с постусловием. В цикле с предусловием условие цикла располагается перед телом цикла. Do Условие Цикла Тело цикла Loop При этом возможна ситуация, когда операторы тела цикла не выполнятся ни разу. Другими словами условие цикла можно сформулировать таким образом, что управление никогда не попадет внутрь цикла. В цикле с постусловием условие расположено после тела цикла. Поэтому операторы тела цикла обязательно выполнятся хотя бы один раз, чтобы выполнение программы могло дойти до проверки условия. Do Тело цикла Loop Условие цикла Вне зависимости от вида цикла его условие может быть записано в одной из двух форм.
While Условное выражение В этом случае операторы тела цикла выполняются, пока Условное выражение имеет значение Истина (True). Цикл завершается, когда Условное выражение принимает значение Ложь (False).
Until Условное Выражение Цикл с таким условием завершается, когда Условное выражение принимает значение Истина (True). Если Условное выражение ложно, то выполнение цикла продолжается. Таким образом, в Visual Basic 2005 возможны четыре различных варианта цикла с условием.
Тело цикла Loop
Тело цикла Loop
Тело цикла Loop While Условное выражение
Тело цикла Loop Until Условное Выражение Меняя Условные выражения, каждый вид цикла можно заменить на любой другой без потери работоспособности программы. Если Условие цикла сформулировано с ошибкой, то программа может попасть в бесконечный цикл. Бесконечный цикл – это цикл, в котором количество повторов ничем не ограничено. В таких случаях говорят, что программа «зациклилась» или «зависла». Чаще всего бесконечный цикл возникает из-за ошибок в условии цикла: условие продолжения всегда имеет значение Истина (True) или условие завершения цикла всегда имеет значение Ложь (False). Прервать программу, попавшую в бесконечный цикл, можно только из среды Visual Basic 2005. Для этого необходимо перейти из окна работающей программы в окно среды Visual Basic 2005 и выбрать команду Stop Debugging из пункта меню Debug. Среди операторов тела цикла может встречаться особый оператор Exit Do. Он прекращает выполнение цикла при любом значении его условия. Выполнение программы продолжается с оператора, стоящего сразу после ключевого слова Loop. 6.2.1. Ввод с проверкойВ качестве примера использования цикла с условием рассмотрим задачу ввода значения переменной с проверкой. Будем вводить с клавиатуры значение переменной n, которое должно находиться в диапазон [3; 20]. Один из способов решения этой задачи мы рассмотрели в разделе 5.9. Тогда фрагмент программы выглядел следующим образом. Dim n As Integer vvod: n = Val(InputBox("Введите число n от 3 до 20")) If n < 3 Or n > 20 Then MsgBox("Неправильное значение") GoTo Vvod End If Решим эту же задачу, используя цикл с постусловием. Сначала воспользуемся циклом с условием Until. В этом случае условие цикла надо сформулировать таким образом, чтобы он прекращал свою работу при правильном значении переменной n. То есть условие цикла – это условие правильности значения переменной. Dim n As Integer Do n = Val(InputBox("Введите число n от 3 до 20")) Loop Until n >= 3 And n <= 20 Теперь рассмотрим использование цикла с условием While. Это условие продолжения цикла, поэтому оно должно быть сформулировано таким образом, чтобы при неправильном значении n цикл выполнялся еще раз. Dim n As Integer Do n = Val(InputBox("Введите число n от 3 до 20")) Loop While n < 3 Or n > 20 Эту же задачу можно решать, используя циклы с предусловием. Но решение получается громоздким и на практике не применяется. 6.2.2. Обработка совокупности чисел с неизвестным числом элементовДругая область использования циклов с условием – это задачи обработки совокупности чисел, в которых количество элементов заранее неизвестно. Существует два вида таких совокупностей. В первом случае ввод чисел прекращается с появлением элемента, имеющего некоторое заранее заданное значение, например, ноль. Во втором случае ограничение на значение элементов отсутствует, но после ввода каждого элемента пользователь отвечает на вопрос, хочет ли он дальше вводить элементы совокупности. Иногда этот вопрос может задаваться не после ввода очередного элемента, а перед ним. Это определяет вид используемого цикла. Если вопрос задается перед вводом элемента, применяется цикл с предусловием. Если вопрос задается после ввода элемента, применяется цикл с постусловием. Алгоритмы обработки совокупности, описанные в разделе 6.1.3, не зависят от ее вида и способа ввода. Поэтому рассмотрим два частных случая обработки совокупностей с неизвестным числом элементов. Найти произведение всех элементов совокупности. Ввод чисел прекращается при появлении элемента, равного нулю. Данную задачу целесообразно решать, используя цикл с предусловием. Так как совокупность заканчивается нулевым элементом, то, очевидно, что последний введенный элемент (ноль) в произведение включать не следует. Поэтому проверка введенного значения должна предшествовать его включению в общее произведение. Элементы совокупности будем вводить, используя функцию InputBox. Элементы совокупности и результаты вычислений будем выводить в окно списка с именем lstA. Для решения задачи нам потребуются следующие переменные: a – элемент совокупности, proiz – искомое произведение, kol – количество элементов в совокупности. Dim a, proiz, kol As Integer Очищаем окно списка от результатов предыдущих запусков программы. lstA.Items.Clear() Задаем начальные значения для произведения и количества. proiz = 1 kol = 0 Вводим первый элемент совокупности. a = Val(InputBox("Введите элемент совокупности")) Проверяем, равен ли введенный элемент нулю. Если да, то выполнение цикла прекращается. Do Until a = 0 Если элемент совокупности не равен нулю, то выводим его значение в окно списка. lstA.Items.Add(Str(a)) Увеличиваем количество элементов совокупности на единицу. kol += 1 И включаем элемент совокупности в общее произведение. proiz *= a Просим пользователя ввести очередной элемент совокупности. a = Val(InputBox("Введите элемент совокупности")) Этот элемент будет обработан при следующем повторе тела цикла. Loop После завершения основного цикла, выводим в окно списка горизонтальную черту, которая позволит зрительно отделить элементы совокупности от результатов вычислений. lstA.Items.Add("----------------------------") Проверяем, есть ли в совокупности ненулевые элементы. If kol = 0 Then Если количество элементов в совокупности равно нулю, значит, первый же введенный элемент был равен нулю. В этом случае мы не можем вычислить произведение элементов. Поэтому вместо значения произведения выводим поясняющее сообщение. lstA.Items.Add("Нет ненулевых элементов") Else В противном случае, выводим значение вычисленного произведения. lstA.Items.Add("Произведение = " + Str(proiz)) End If Полный текст программы приведен в приложении 15. Примеры работы программы представлены на рис. 29. Рис. 29. Примеры работы программы обработки совокупности, ограниченной нулем Найти сумму все элементов последовательности. После ввода каждого числа пользователю задается вопрос, хочет ли он продолжить ввод чисел. Для решения этой задачи будем использовать цикл с постусловием, так как вопрос пользователю задается после ввода очередного элемента. Сам алгоритм вычисления суммы элементов совокупности ничем не отличатся от аналогичного алгоритма, разработанного для совокупности с известным числом элементов. Элементы совокупности будем вводить, используя функцию InputBox. Элементы совокупности и результаты вычислений будем выводить в окно списка с именем lstA. Для решения задачи нам потребуются три целочисленных переменных: a – элемент совокупности, summa – искомая сумма элементов, otvet – для хранения и обработки ответа пользователя на запрос о повторном вводе. Dim a, summa, otvet As Integer Очищаем окно списка от результатов предыдущих запусков программы. lstA.Items.Clear() Задаем начальное значение суммы. summa = 0 Организуем основной цикл. Do Вводим очередной элемент совокупности. a = Val(InputBox("Введите элемент совокупности")) Выводим его значение в окно списка. lstA.Items.Add(Str(a)) Добавляем значение элемента совокупности к ранее накопленной сумме. summa += a Спрашиваем у пользователя, хочет ли он еще вводить элементы совокупности. otvet = MsgBox("Еще вводить числа?", 32 + 4) Анализируем ответ пользователя. Если пользователь ответил «Нет», то в переменную otvet будет записано число 7 (см. раздел 4.10). В этом случае основной цикл завершает свою работу. Loop Until otvet = 7 После завершения основного цикла, выводим в окно списка горизонтальную черту, которая позволит зрительно отделить элементы совокупности от результатов вычислений. lstA.Items.Add("----------------------------") В окно списка выводим вычисленную сумму всех элементов совокупности. lstA.Items.Add("Сумма = " + Str(summa)) Полный текст программы представлен в приложении 16. Пример работы программы приведен на рис. 30. Рис. 30. Пример обработки совокупности с неизвестным числом элементов 6.2.3. Вычисление суммы ряда по общей формулеОдной из основных областей применения циклов с условием являются приближенные математические вычисления, например, вычисление суммы ряда и решение нелинейных уравнений. Изучим особенности программной реализации некоторых из этих задач и начнем с задачи вычисления суммы бесконечного сходящегося ряда. Рассмотрим ряд , где n = 1, 2, 3,… Требуется найти сумму ряда в некоторой заранее заданной точке x с определенной точностью ε. Исходными данными для этой задачи являются значение x и необходимая точность вычислений ε. Параметр «точность вычислений» означает, что слагаемые, которые по модулю меньше точности, считаются несущественными и в общую сумму не включаются. Для ввода исходных данных будем использовать функцию InputBox. Результатом программы является значение накопленной суммы. Но для проверки правильности вычислений мы будем еще выводить значение левой части выражения, номер и значение последнего слагаемого, вошедшего в сумму. Для вывода результатов будем использовать окно списка с именем lstA. Для решения этой задачи нам потребуется организовать цикл с условием. На каждом шаге цикла мы будем по общей формуле вычислять значение очередного слагаемого и прибавлять его к общей сумме. Как только очередное слагаемое станет меньше заданной точности, мы закончим выполнение цикла. Рассмотрим особенности программной реализации этого алгоритма. Для решения задачи нам потребуются следующие переменные: x – точка, в которой вычисляется сумма ряда, eps – требуемая точность вычислений, summa – искомая сумма ряда, slag – очередное слагаемое. Все эти переменные имеют рациональный тип данных. Для повышения точности наших вычислений будем использовать тип Double. Dim x, summa, slag, eps As Double Для вычисления факториала, стоящего в знаменателе дроби, заведем переменную f, которая будет иметь целый тип с максимально возможной емкостью – ULong. Dim f As ULong Так как для вычисления факториала необходимо организовать цикл, то нам потребуется специальная переменная – счетчик i. Заметим, что формула общего члена ряда зависит от номера слагаемого – n. Поэтому при решении задачи нам потребуется переменная для хранения номера очередного слагаемого. Назовем ее n. Она будем иметь целый тип данных. Dim n, i As Integer Работа программы начинается с очистки окна списка от ее предыдущих результатов. lstA.Items.Clear() Вводим исходные данные. x = Val(InputBox("Введите точку")) eps = Val(InputBox("Введите точность")) Задаем начальные значения. Начальное значение суммы равно нулю. Номер текущего слагаемого тоже равен нулю, так как никакого слагаемого на данный момент времени мы не вычислили. summa = 0 n = 0 Организуем основной цикл. Do На каждом шаге цикла будем вычислять очередного слагаемое. При этом его номер будет на единицу больше, чем на предыдущем шаге. n += 1 Начинаем вычислять значение очередного слагаемого. Первым шагом будет вычисление факториала, стоящего в знаменателе дроби. f = 1 For i = 2 To 2 * n - 1 f *= i Next Затем по общей формуле вычисляем само слагаемое, заменяя факториал на уже найденное значение. slag = (-1) ^ (n + 1) * x ^ (2 * n - 1) / f Полученное слагаемое добавляем к общей сумме. summa += slag Проверяем, если модуль слагаемого меньше заданной точности, то дальнейшие вычисления не приведут к заметным изменениям результата, и выполнение цикла можно завершить. Loop Until Math.Abs(slag) <= eps Выводим в окно списка полученную сумму, значение выражения, стоящего в левой части равенства, номер и значение последнего слагаемого. lstA.Items.Add("summa=" + Str(summa)) lstA.Items.Add("sin(x)=" + Str(Math.Sin(x))) lstA.Items.Add("n=" + Str(n)) lstA.Items.Add("Последнее слагаемое =" + Str(slag)) Полный текст программы представлен в приложении 17. Пример работы программы приведен на рис. 31. Исходные данные для этого случая: x = 1, eps = 1e-4 = 10-4. Рис. 31. Пример работы программы вычисления суммы ряда по общей формуле
Вычисление суммы ряда по общей формуле, рассмотренное в предыдущем разделе, безусловно, является общим способом решения подобных задач. Но иногда процесс вычислений можно существенно упростить, построив рекуррентное соотношение для вычисления очередного слагаемого. В этом случае каждое слагаемое вычисляется как некоторая функция, зависящая от одного или нескольких предыдущих членов ряда. Построим рекуррентное соотношение для следующего ряда. , где Сначала запишем формулы для слагаемых с номерами n и n - 1. Вычислим отношение . Таким образом, мы получили, что Отсюда можно легко получить рекуррентное соотношение для вычисления очередного слагаемого. В этой формуле sn – очередное слагаемое, sn-1 – предыдущее слагаемое, x – точка, в которой вычисляется сумма ряда, n – номер очередного слагаемого. Используя полученную рекуррентную формулу, найдем сумму ряда в некоторой заранее заданной точке x с определенной точностью ε. Так же как и предыдущем случае, исходными данными будут значение x и необходимая точность вычислений ε. Для ввода исходных данных будем использовать функцию InputBox. Результатом программы является значение накопленной суммы. Но для проверки правильности вычислений мы будем еще выводить значение левой части выражения, номер и значение последнего слагаемого, вошедшего в сумму. Для вывода результатов будем использовать окно списка с именем lstA. Для решения этой задачи нам потребуется организовать цикл с условием. На каждом шаге цикла мы будем по рекуррентной формуле вычислять значение очередного слагаемого и прибавлять его к общей сумме. Как только очередное слагаемое станет меньше заданной точности, мы закончим выполнение цикла. Рассмотрим особенности программной реализации этого алгоритма. Для решения задачи нам потребуются следующие переменные: x – точка, в которой вычисляется сумма ряда, eps – требуемая точность вычислений, summa – искомая сумма ряда, slag – очередное слагаемое. Все эти переменные имеют рациональный тип данных. Для повышения точности наших вычислений будем использовать тип Double. Dim x, summa, slag, eps As Double Так как рекуррентная формула зависит от номера очередного слагаемого, то для его хранения заведем переменную n. Dim n As Integer Очищаем окно списка. lstA.Items.Clear() Вводим исходные данные. x = Val(InputBox("Введите точку")) eps = Val(InputBox("Введите точность")) Задаем начальные значения переменных. Номер первого слагаемого равен единице. n = 1 По формуле ряда определяем первое слагаемое. slag = x Итоговую сумму полагаем равной первому слагаемому. summa = slag Организуем основной цикл. Do На каждом шаге мы вычисляем очередное слагаемое. При этом его номер будет на единицу больше, чем на предыдущем шаге. n += 1 Используя рекуррентное соотношение, вычисляем очередное слагаемое. slag = -slag * x ^ 2 / ((2 * n - 2) * (2 * n - 1)) И добавляем его к итоговой сумме. summa += slag Проверяем, если модуль слагаемого меньше заданной точности, то дальнейшие вычисления не приведут к заметным изменениям результата, и выполнение цикла можно завершить. Loop Until Math.Abs(slag) <= eps Выводим в окно списка полученную сумму, значение выражения, стоящего в левой части равенства, номер и значение последнего слагаемого. lstA.Items.Add("summa=" + Str(summa)) lstA.Items.Add("sin(x)=" + Str(Math.Sin(x))) lstA.Items.Add("n=" + Str(n)) lstA.Items.Add("Последнее слагаемое =" + Str(slag)) Полный текст программы представлен в приложении 18. Пример работы программы приведен на рис. 32. Исходные данные для этого случая: x = 1, eps = 1e-4 = 10-4. Рис. 32. Пример работы программы вычисления суммы ряда с использованием рекуррентного соотношения 6.2.5. Вычисление произведения рядаВычисление произведения ряда во многом похоже на вычисление ряда по общей формуле. Только вместо накопления суммы мы будем использовать прием накопления произведения. Соответственно изменятся начальное значение итоговой переменной (оно станет равным единице) и условие завершения цикла. Основной цикл должен завершиться тогда, когда очередной сомножитель будет отличаться от единицы не более чем на заданную величину, которая и является точностью вычислений ε. Рассмотрим задачу вычисления произведения ряда в некоторой заранее заданной точке x с определенной точностью ε. Для ввода исходных данных будем использовать функцию InputBox. В качестве результатов будем выводить итоговое произведение, значение левой части выражения, номер и значение последнего сомножителя. Для проверки правильности работы программы на каждом шаге цикла будем выводить его номер и накопленное значение произведения. Для решения задачи нам потребуются следующие переменные: x – точка, в которой вычисляется сумма ряда, eps – требуемая точность вычислений, proiz – искомое произведение, p – очередной сомножитель. Все эти переменные имеют рациональный тип данных. Для повышения точности наших вычислений будем использовать тип Double. Dim x, proiz, p, eps As Double Так как общая формула члена ряда зависит от номера сомножителя, то для его хранения заведем переменную n. Dim n As Integer Очищаем окно списка. lstA.Items.Clear() Вводим исходные данные. x = Val(InputBox("Введите точку")) eps = Val(InputBox("Введите точность")) Задаем начальные значения переменных. Обратите внимание, что начальное значение для произведения – единица. proiz = 1 Номер текущего сомножителя равен нулю, так как никакого сомножителя на данный момент времени мы не вычислили. n = 0 Организуем основной цикл. Do На каждом шаге цикла номер очередного сомножителя увеличивается на единицу. n += 1 По общей формуле вычисляем очередной сомножитель. p = 1 - 4 * x ^ 2 / ((2 * n - 1) ^ 2 * Math.PI ^ 2) Включаем его в итоговое произведение. proiz *= p Для проверки правильности работы программы выводим в окно списка номер шага цикла (он совпадает с номером текущего сомножителя) и накопленное значение произведения. Использование константы vbTab позволяет организовать вывод информации в две колонки. lstA.Items.Add(Str(n) + vbTab + Str(proiz)) Проверяем, если текущий сомножитель отличается от единицы меньше, чем на величину заданной точности, то дальнейшие вычисления не приведут к заметным изменениям результата, и выполнение цикла можно завершить. Loop Until Math.Abs(1 - p) <= eps Выводим горизонтальную черту, чтобы зрительно отделить результаты программы от промежуточных значений. lstA.Items.Add("----------------------------------") В окно списка выводим итоговое значение произведения, значение левой части выражения, номер и значение последнего сомножителя. lstA.Items.Add("Произведение =" + Str(proiz)) lstA.Items.Add("cos(x)=" + Str(Math.Cos(x))) lstA.Items.Add("n=" + Str(n)) lstA.Items.Add("Последний сомножитель =" + Str(p)) Полный текст программы представлен в приложении 19. Пример работы программы приведен на рис. 33. Исходные данные для этого случая: x = 1, eps = 1e-3 = 10-3. Рис. 33. Пример работы программы вычисления произведения ряда
Рассмотрим еще один пример использования цикла с условием. Это один из наиболее распространенных способов решения нелинейных уравнений вида . Он называется метод простой итерации. Исходя из особенностей решаемой задачи, выбирается некоторое начальное приближение к решению уравнения. Как правило, оно обозначается x0. Все последующие приближения к корню уравнения вычисляются по формуле , где xk – очередное приближение к корню уравнения, xk-1 – предыдущее приближение к корню уравнения. Процесс продолжается до тех пор, пока расстояние между точками xk и xk-1 не станет меньше некоторого заранее заданного числа, которое является требуемой точностью вычислений ε. Схема работы метода простой итерации приведена на рис. 34. Рис. 34. Метод простой итерации Рассмотрим особенности программой реализации данного алгоритма. Требуется решить уравнение методом простой итерации с заданной точностью. Начальное значение x0 = 0,5. Единственным исходным данным для этой задачи является требуемая точность вычислений ε. Для ее ввода будем использовать функцию InputBox. Результатами программы будут значение корня уравнения, значение его правой части и количество потребовавшихся шагов цикла. Для проверки правильности работы программы на каждой итерации будем выводить номер шага и текущее значение корня уравнения. Весь вывод информации будем осуществлять с помощью окна списка с именем lstA. Для решения задачи нам потребуются следующие переменные: xTek – очередное приближение к корню уравнения, xPred – предыдущее приближение к корню уравнения, eps – требуемая точность вычислений. Все эти переменные имеют рациональный тип данных. Для повышения точности наших вычислений будем использовать тип Double. Dim xTek, xPred, eps As Double Так как на каждой итерации требуется выводить ее номер, то для его хранения потребуется целочисленная переменная. Назовем ее n. Dim n As Integer Очищаем окно списка. lstA.Items.Clear() Вводим требуемую точность вычислений. eps = Val(InputBox("Введите точность")) Задаем начальное приближение к корню уравнения. xTek = 0.5 Начальное приближение также называют нулевым. Поэтому номер итерации равен нулю. n = 0 Организуем основной цикл. Do В окно списка выводим номер итерации и значение текущего приближения к корню уравнения. Использование константы vbTab позволяет организовать вывод информации в две колонки. lstA.Items.Add(Str(n) + vbTab + Str(xTek)) Вычисляем очередное приближение к корню уравнения. Запоминаем значение текущего приближения как предыдущее приближение к корню уравнения. xPred = xTek При переходе на следующую итерацию ее номер увеличивается на единицу. n += 1 По методу простой итерации вычисляем новое приближение к корню уравнения. Для этого подставляем значение предыдущего приближения в выражение, стоящее в правой части уравнения. xTek = Math.Cos(xPred) Проверяем, насколько мало расстояние между текущим и предыдущим приближениями. Если это расстояние меньше требуемой точности вычислений, значит, мы нашли корень уравнения с нужной точностью, и процесс вычислений можно остановить. Loop Until Math.Abs(xTek - xPred) < eps Выводим горизонтальную черту, чтобы зрительно отделить результаты работы программы от промежуточных значений. lstA.Items.Add("-----------------------------------") В окно списка выводим полученные результаты: значение последнего приближения к корню уравнения, значение правой части уравнения и количество выполненных итераций (оно совпадает с количеством повторов цикла). Если программа написана правильно, то разница между первыми двумя числами будет незначительной. lstA.Items.Add("x =" + Str(xTek)) lstA.Items.Add("cos(x) =" + Str(Math.Cos(xTek))) lstA.Items.Add("Количество шагов =" + Str(n)) Полный текст программы представлен в приложении 20. Пример работы программы приведен на рис. 35. Исходные данные для этого случая: eps = 10-3. Рис. 35. Пример работы программы решения нелинейного уравнения |