Онлайн час в Google Meet
Лого на 91. НЕГ „Проф. Константин Гълъбов“

11. клас · Модул 1 · Урок 12

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

while с предусловие и do-while с постусловие, UML диаграмата на цикъла и как всеки цикъл се моделира с друг. Алгоритъм на Евклид и численият метод за квадратен корен.

Защо ни е това

Операторът for вече го познаваш. Той е подходящ, когато тялото на цикъла трябва да се изпълни за определени стойности на някаква управляваща променлива или определен брой пъти.

Но много често не знаем предварително колко пъти ще се завърти цикълът. Колко години трябва да мине, докато продукцията падне под 10 тона? Колко деления прави алгоритъмът на Евклид? За такива случаи C# предлага две други възможности.

Операторът while

while (докато)

while (<условие>) { <тяло на цикъла> } — проверява стойността на логическия израз и ако тя е true, изпълнява тялото. Продължава да прави това, докато условието е изпълнено. Когато за пръв път стойността стане false, операторът прекратява работа и предава управлението на следващия оператор.

Тъй като в while условието се проверява преди да се изпълни тялото на цикъла, за оператора казваме, че цикълът е с предусловие.

предишен операторусловиеfalsetrueтяло на цикъласледващ оператор
Фиг. 1. UML диаграма на цикъл с предусловие.

Операторът do-while

do-while

do { <тяло на цикъла> } while (<условие>); — условието за край на цикъла се проверява след всяко изпълнение на тялото му. Затова казваме, че този цикъл е с постусловие.

Всеки цикъл може да се напише с друг

Не е невъзможно да се моделира работата на кой да е оператор за цикъл с някой от другите, макар че понякога това ще бъде доста изкуствено и често ненужно. Ето еквивалентността на for и while:

forwhile
Записва се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новото xxs − x≥ eps?
начало—4,50——
14,503,251,25да → продължава
23,253,00961538…0,24…да → продължава
33,00961538…3,00001536…0,0096…да → продължава
43,00001536…3,000000000039320,00001536…не → край

Извежда се 3,00000000003932. Забележи колко бързо стойността се доближава до 3.

Въпроси

Какво трябва да запомниш

  • while е с предусловие — тялото може да не се изпълни нито веднъж.
  • do-while е с постусловие — тялото се изпълнява поне веднъж, каквото и да е условието.
  • Всеки цикъл може да се моделира с друг: while (true) плюс break дава постусловие.
  • Алгоритъмът на Евклид: заменяш (a, b) с (b, a % b), докато b стане 0.
  • Численият метод дава приблизителен отговор. Спира се, когато разликата между две последователни приближения падне под зададена точност eps.