|
Главная » 2010 » Февраль » 11 » Цикл while
|
Цикл while Цикл while очень похож на цикл do, однако у него имеется одно важное отли- чие: вычисление логического условия в цикле while происходит в начале цикла, а не в конце. Если в результате проверки условия будет получено значение false, то цикл while вообще не будет выполняться и управление передается коду, расположенному после этого цикла. 68 Глава 4 Цикл while оформляется следующим образом: while {<условие>) Он может использоваться практически так же, как и цикл do. Например: int i = 1; while (i <= 10) Console.WriteLine('{0}", i Выполнение этого кода приведет к тому же результату: числа от 1 до 10 будут вы- ведены в столбец. Давайте изменим программу так, чтобы в ней использовался цикл while. Практикум: использование цикла while 1. Откройте консольное приложение с именем chO4ExO5 В директории C:\BegCSharp\Chapter4. 2. Модифицируйте код следующим образом (в качестве отправной точки используйте код из СпО4ЕхО4 И не забудьте удалить оператор while ^ в конце исходного цикла): static void Main (string [] args) double balance, interestRate, targetBalance; Console.WriteLine(*What is your current balance?"); balance = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("What is your current annual interest rate (in %)?"); interestRate = 1 + Convert.ToDouble(Console.ReadLine()) / 100.0; Console.WriteLine(*What balance would you like to have?") ; targetBalance = Convert.ToDouble(Console.ReadLine()); int totalYears = 0; while (balance < targetBalance) balance *= interestRate; ++totalYears; Console.WriteLine(*In {0} year{l} you'll have a balance of {2}.", totalYears, totalYears == 1 ? •• : "s", balance); 3. Запустите программу еще раз, однако теперь введите требуемый баланс меньше начального: what xs «/our current balance? 10000 Uhat is t/our current annual interest rate <±n x>l 4.2 Uhat balance Mould you like to have? 1000 In Ш years you*11 have a balance of 10008. ;Press any key to continue Управление порядком выполнения 69 Как это работает Простая замена цикла do циклом while позволила решить проблему, возник- шую в предыдущем примере. Переместив проверку логического условия в начало цикла, мы предусмотрели ситуацию, при которой вообще не требуется выполнять цикл и можно сразу перейти к выводу результата. Конечно, в данном случае существуют и альтернативные варианты. Например, можно осуществлять проверку вводимой пользователем информации, чтобы убе- диться в превышении начальной суммы конечным балансом. Для этого поместим в цикл соответствующий код: Console.WriteLineCWhat balance would you like to have?') ; { targetBalance = Convert.ToDouble(Console.ReadLine()); if (targetBalance <= balance) \ Console.WriteLineCYou must enter an amount greater than * + "your current balanceJ\nPlease enter another value.*); } while (targetBalance <- balance); Это позволит отвергнуть значения, лишенные смысла, и выходной поток будет выглядеть так: iUluvt is 5?сш*% cuiTent balance? 110080 itfhat is your current annual int,, |4.2 lilbat balance t*ould you like to have? 11800 \4oii must enter ar* anoiint greater than your current balance? 1Р1е«л»е enter anotber value. 50880 In 40 деагз you'll have a balance of 5i84S.2243976121. i>««*>s arij^ ke^? to continite Проверка допустимости информации, вводимой пользователем, является важ- ным моментом при разработке приложений; по ходу книги вам встретится много таких примеров. Цикл for Последний тип цикла, который рассматривается в данной главе,— это цикл for. Он относится к тому типу циклов, которые выполняются заранее заданное количе- ство раз и сами отвечают за организацию счетчика цикла. Для организации цикла for требуется следующая информация: • Начальное значение для инициализации переменной цикла • Условие для продолжения выполнения цикла, зависящее от переменной цикла • Операция, которая будет выполняться над переменной цикла по завершении очередного прохода цикла Например, если необходимо организовать цикл с переменной цикла, изменяю- щейся от 1 до 10 с шагом, равным единице, то в этом случае начальное значение 70 Глава 4 равно 1, условием для продолжения цикла будет "переменная цикла меньше или равна 10м, а операцией, выполняющейся по окончание каждого прохода цикла, бу- дет прибавление значению переменной цикла единицы. Эта информация должна быть размещена в структуре цикла for следующим образом: for {<итщиализация>} <условие>; <операция>) { ; ' • <код, выполняющийся в цикле> • ; Ш 1 - Ф : Ш ^ , •••••-•• :,:• ;:;;:="= •••: j>:"-- v-J Этот код работает так же, как и следующий цикл while: ., • .J:,: :: .. . : . 'Л : ' : . <код, выполняющийся в цикле> <операцня> • • ,,-ШШШШ Однако формат цикла for оказывается более понятным, поскольку все необхо- димые параметры, определяющие цикл, собраны воедино, а не распределены по разным операторам. При рассмотрении циклов do и while мы приводили пример с выводом чисел от 1 до 10. Давайте взглянем на код, позволяющий сделать то же самое с помощью цикла for: int i; for (i = 1; i <= 10; ++i) Console.WriteLine(*{0}•, i) ; Целой переменной цикла с именем i присваивается начальное значение 1, после чего она увеличивается на 1 в конце каждого прохода. В теле цикла происходит вывод значения i на консоль. Обратите внимание, что когда начинает выполняться код, расположенный за циклом, переменная i обладает значением, равным 11. Дело в том, что в конце прохода цикла, в котором переменная i равняется 10, ее значение увеличивается на единицу до проверки условия i <= ю. Очевидно, что после проверки выполне- ние цикла прекращается. Как и циклы while, циклы for выполняются только в том случае, если провер- ка условия дает true перед первым проходом цикла, т. е. код, находящийся внутри цикла, может вообще ни разу не выполняться. В заключение отметим, что у нас имеется возможность объявить переменную цикла в качестве составной части оператора for, для чего вышеприведенный при- мер следует переписать следующим образом: for (int i = 1; I <= 10; ++i) Console.WriteLine('{0}*, i) ; В этом случае переменная i будет недоступна коду, находящемуся вне цикла (подробнее об этом см. главу 6, раздел "Область действия переменных"). Давайте рассмотрим пример использования цикла for. Поскольку мы уже до- статочно хорошо знакомы с циклами, постараемся сделать его более интересным: в нем будет выводиться множество Мандельброта (Mandelbrot set) (правда, с по- мощью обыкновенных текстовых символов, что, конечно, выглядит не так захваты- вающе). Управление порядком выполнения 71 Практикум: использование цикла for 1. Создайте новое консольное приложение с именем chO4ExO6 В директории C:\BegCSharp\Chapter4. 2. Добавьте следующий код в ciassi.cs: static void Main(string[] args) , double realCoord, imagCoord; double realTemp, imagTemp, realTemp2, arg; int iterations; for (imagCoord = 1.2; imagCoord >= -1.2; imagCoord -= 0.05) for (realCoord = -0.6; realCoord <= 1.77; realCoord += 0.03) iterations = 0; realTemp = realCoord; imagTemp = imagCoord; arg = (realCoord * realCoord) + (imagCoord * imagCoord); while ((arg < 4} && (iterations < 40)) realTemp2 = (realTemp * realTemp) - (imagTemp * imagTemp) - realCoord; imagTemp - (2 * realTemp * imagTemp) - imagCoord; realTemp = realTemp2; arg = (realTemp * realTemp) + (imagTemp * imagTemp); iterations += 1; switch (iterations % 4) case 0: Console.Write(".»); break; c a s e 1 : • . .. • ' • • . . . , . ; .. • •• .• ..-: : , : : , • • . • • • .• • • ' • : • . . . • Console.Write Co") ; break; case 2: Console.Write("0я); ' break; ' ;;:'; •.;.:; -;• ••;;;;y ":. ;' ' c a s e 3 : V ; ':' ' :;' '; :' '• :' V [ • ' • Conscle.Write(*@"); ; break; . Console.WriteCXn") ; 3. Запустите программу (см. рис. справа). Как это работает Сейчас мы не будем подробно описывать, ка- ким образом вычисляются множества Мандель- брота, однако основные моменты необходимо объяснить для понимания роли циклов в этой программе. Если вы не интересуетесь математи- кой, то можете смело пропустить следующие два абзаца, поскольку в данном случае самое важное — это понять, как устроена программа. 72 Глава 4 Каждая точка на рисунке Мандельброта соответствует комплексному числу вида N = х + y*i, где х — это действительная часть, у — мнимая часть, a i — ко- рень квадратный из - 1 . Координаты х и у рисунка соответствуют действительной и мнимой частям комплексного числа. Для каждой точки рисунка рассматривается аргумент N, который представляет собой корень квадратный из х*х + у*у. Если это значение больше или равно 2, то данная позиция имеет значение 0. Если же аргумент числа N меньше двух, то про- исходит замена N на N*N - N (что дает N - (х*х - у*у-х) + (2*х*у - y)*i) и снова выполняется проверка числа N. Если это значение оказывается большим или рав- ным 2, позиция, соответствующая этому числу, будет иметь значение 1. Этот про- цесс продолжается до тех пор, пока данной точке рисунка не удастся присвоить некое число либо пока не будет превышено заранее заданное число итераций. Основываясь на значениях, присвоенных каждой точке рисунка, в графической среде каждой точке на экране можно сопоставить пиксель определенного цвета. Однако поскольку мы используем алфавитно-цифровой дисплей, то будем просто выводить на экран различные символы. Давайте рассмотрим код и содержащиеся в нем циклы. В первую очередь мы объявили переменные, необходимые для дальнейших вы- числений: double realCoord, imagCoord; double realTemp, imagTemp, realTemp2, arg; int iterations; Здесь reaicoord и imagCoord представляют действительную и комплексную час- ти числа N, а остальные переменные типа double предназначены для хранения про- межуточной информации, получающейся в процессе вычислений. В переменной iterations хранится количество итераций, потребовавшееся для того, чтобы аргу- мент N (arg) стал большим или равным 2. Далее мы организовали два цикла for, которые позволяют пройти по всем ко- ординатам нашего изображения (в них для изменения счетчиков циклов использу- ется более сложный, чем у операторов 4-+ и —, синтаксис): for (imagCoord = 1.2; imagCoord >= -1.2; imagCoord -= 0.05) { for (realCoord • -0.6; realCbord <= 1.77; realCoord += 0.03) { Автор специально подобрал границы, которые позволяют продемонстрировать основную часть множества Мандельброта. Если у вас возникнет желание "увели- чить" это изображение, то можете поэкспериментировать с границами сами. Внутри этих двух циклов располагается код, относящийся к единственной точке множества Мандельброта и дающий то значение N, с которым ведется дальнейшая работа. Именно здесь вычисляется количество необходимых итераций и значение символа, выводимого в данной точке. Сначала производится инициализация нескольких переменных: iterations = 0; realTemp = realCoord; imagTemp = imagCoord; arg = (realCoord * realCoord) + (imagCoord * imagCoord); Затем для осуществления итерационного процесса используется цикл while, а не цикл do, так как если начальное значение N больше 2, искомым ответом явля- ется iterations = о и никаких дополнительных вычислений не требуется. Управление порядком выполнения 73 Обратите внимание, что в программе не производится полное вычисление аргу- мента: вычисляется значение х*х + у*у, а затем проверяется, меньше ли оно 4. Такой подход позволяет упростить вычисления, поскольку заранее известно, что 2 — это корень квадратный из 4, и, следовательно, нет необходимости вычис- лять квадратные корни в самой программе: while ((arg < 4) && (iterations < 40) ) { realTemp2 = (realTemp * realTemp) - (imagTemp * imagTemp) - realCoord; imagTemp = (2 * realTemp * imagTemp) - imagCoord; realTemp = realTemp2; arg = (realTemp * realTemp) + (imagTemp * imagTemp) ; iterations += 1; } Максимальное число повторений данного цикла равно 40. Получив значение для данной точки в переменной iterations, используем опе- ратор switch для выбора символа, который будет выводиться в этой точке. Вместо сорока возможных значений здесь участвуют всего четыре разных символа, кото- рые определяются с помощью оператора взятия по модулю (%) таким образом, что значения 0, 4, 8... выводятся одним символом, значения 1, 5, 9... другим сим- волом и т. д.: switch (iterations % 4) { case 0: Console.WriteC"); break; case 1: Console.Write Co") ; break; case 2: Console.Write(*О*); break; case 3: Console.Write(*§"); break; } Обратите внимание, что вместо оператора console.writeLineо используется console, write о , поскольку после вывода очередного символа не требуется пере- ходить на новую строку. Необходимость перейти на новую строку возникает после выполнения самого вложенного цикла, и здесь просто выводится символ конца строки, для чего при- меняется уже знакомая escape-последовательность: } Console.Write("\п*); } В итоге каждая строка программы отделена от предыдущей и выровнена надле- жащим образом. Конечный результат данного приложения оказывается не очень красивым, но весьма впечатляющим; во всяком случае, он демонстрирует, насколько полезным может быть использование циклов и ветвления в программах.
|
Категория: информатика |
Просмотров: 1484 |
Добавил: basic
| Рейтинг: 0.0/0 |
|
Статистика
Онлайн всего: 1 Гостей: 1 Пользователей: 0
|