Защо ни е това
Операторът for вече го познаваш. Той е подходящ, когато тялото на цикъла трябва да се изпълни за определени стойности на някаква управляваща променлива или определен брой пъти.
Но много често не знаем предварително колко пъти ще се завърти цикълът. Колко години трябва да мине, докато продукцията падне под 10 тона? Колко деления прави алгоритъмът на Евклид? За такива случаи C# предлага две други възможности.
Операторът while
while (докато)
while (<условие>) { <тяло на цикъла> } — проверява стойността на логическия израз и ако тя е true, изпълнява тялото. Продължава да прави това, докато условието е изпълнено. Когато за пръв път стойността стане false, операторът прекратява работа и предава управлението на следващия оператор.
Тъй като в while условието се проверява преди да се изпълни тялото на цикъла, за оператора казваме, че цикълът е с предусловие.
Операторът do-while
do-while
do { <тяло на цикъла> } while (<условие>); — условието за край на цикъла се проверява след всяко изпълнение на тялото му. Затова казваме, че този цикъл е с постусловие.
Всеки цикъл може да се напише с друг
Не е невъзможно да се моделира работата на кой да е оператор за цикъл с някой от другите, макар че понякога това ще бъде доста изкуствено и често ненужно. Ето еквивалентността на for и while:
| for | while | |
|---|---|---|
| Записва се | for (<инициализация>; <условие>; <обновяване>) { <тяло> } | <инициализация>; while (<условие>) { <тяло> <обновяване> } |
| Проверката е | Преди тялото | Преди тялото |
| Подходящ, когато | Броят повторения се знае предварително | Броят повторения зависи от данните |
Обратното — да получим постусловие от предусловие — става с break, който вече познаваш. Организираме безкраен цикъл с предусловие константата true, който да прекратим, когато постусловието вече не е истина. За целта на постусловието правим неговото отрицание:
while (true)
{
<тяло на цикъла>
if (!<условие>) break;
}Друг полезен оператор при организацията на цикли е continue. Когато се стигне до него, изпълнението на тялото се преустановява и се преминава към следваща стъпка на цикъла. Същото моделиране може да стане и така:
while (true)
{
<тяло на цикъла>
if (<условие>) continue;
else break;
}Задача 1 — фирмата
Условие. Фирма произвела през 2010 г. 130 тона продукция. Всяка от следващите години производството спадало с 10%. Определи през коя година то за първи път ще е под 10 тона.
Решение. Използваме две променливи — дробна x за продукцията и цяла g за поредната година. На всяка стъпка намаляваме x с 10% и увеличаваме g с 1. Изпълняваме цикъла, докато съдържанието на x стане по-малко от 10.
x = 130.0
g = 2010
докато x >= 10
повтори
x = 0.9 * x
g = g + 1
край
изведи gЗадача 2 — най-голям общ делител
Условие. По зададени две положителни цели числа a и b, a > b, намери техния най-голям общ делител.
Решение. Използваме бързата версия на алгоритъма на Евклид. Тя се основава на следното математическо свойство: нека a = k·b + r, където r е остатъкът при деление на a с b. Тогава:
НОД(a, b) = НОД(b, r)
Например: НОД(30, 12) = НОД(12, 6) = НОД(6, 0) = 6Свойството поражда цикличен процес: започва със зададените a и b, на всяка стъпка намира остатъка r при деление на a с b и замества a с b, а b с r. Процесът завършва, когато намереният остатък е 0 — тогава стойността на НОД е текущата стойност на a.
while (b != 0)
{
r = a % b;
a = b;
b = r;
}
// Отговорът е в a.Задача 3 — квадратен корен по числен метод
Условие. Напиши приложение, което изчислява квадратен корен на зададено цяло число a.
Тук ще използваме изчислителна процедура, доста различаваща се от алгоритмите, които вече познаваш. Такава процедура се нарича числен метод. Пресмятаме последователно елементите на безкрайна редица по правилото:
x₁ = a / 2
x₂ = (x₁ + a/x₁) / 2
x₃ = (x₂ + a/x₂) / 2
...
xᵢ₊₁ = (xᵢ + a/xᵢ) / 2Такъв начин на задаване на елементите на безкрайна редица се нарича рекурентна зависимост. Доказано е, че всеки следващ елемент е все по-близо до квадратния корен на a.
Проблемът при такава процедура е кога да се прекрати изпълнението на цикъла. Тъй като стойностите на редицата непрекъснато намаляват, както и разликата между всеки два последователни елемента, цикълът може да спре, когато разликата между два съседни члена стане по-малка или равна на някакво много малко число. Това число се нарича приближение или точност на численя метод. По традиция се означава с гръцката буква ε (епсилон) — оттам и името на променливата eps.
0) нека eps = 0.001
1) въведи a
2) x = a / 2.0
3) повтаряй
4) xs = x
5) x = (x + a/x) / 2
6) докато xs - x >= eps
7) изведи xРолята на променливата xs е важна: в първата стъпка от тялото на цикъла в нея се съхранява предишната стойност на x, а в следващия оператор в x се изчислява новата стойност.
Проследяване за a = 9
| Стъпка | xs | новото x | xs − x | ≥ eps? |
|---|---|---|---|---|
| начало | — | 4,50 | — | — |
| 1 | 4,50 | 3,25 | 1,25 | да → продължава |
| 2 | 3,25 | 3,00961538… | 0,24… | да → продължава |
| 3 | 3,00961538… | 3,00001536… | 0,0096… | да → продължава |
| 4 | 3,00001536… | 3,00000000003932 | 0,00001536… | не → край |
Извежда се 3,00000000003932. Забележи колко бързо стойността се доближава до 3.
Въпроси
Какво трябва да запомниш
whileе с предусловие — тялото може да не се изпълни нито веднъж.do-whileе с постусловие — тялото се изпълнява поне веднъж, каквото и да е условието.- Всеки цикъл може да се моделира с друг:
while (true)плюсbreakдава постусловие. - Алгоритъмът на Евклид: заменяш (a, b) с (b, a % b), докато b стане 0.
- Численият метод дава приблизителен отговор. Спира се, когато разликата между две последователни приближения падне под зададена точност
eps.