Створення програм, що містять цикли з лічильником

Учимося застосовувати цикли з лічильником до різних задач

Від програм з виведенням наперед заданих значень (зірочки, валентинки, задане слово...) перейдемо до створення програм, в яких виводжуваний результат буде формуватися в ході виконання самого циклу.

Завдання 30

Користувач уводить з клавіатури натуральне число. Скласти програму, яка виведе перші 20 чисел натурального ряду, які поділяються на це число

Очевидно, що першим числом натурального ряду чисел, яке поділятиметься на дане число, буде саме це число. Якщо ввести, наприклад, число 11, то першим число, яке поділятиметься на 11 буде саме число 11 (11:11=1). Яке число наступне? А яке число треба розділити на 11, щоб отримати у відповіді 2? Зрозуміло, що це число 22 (22:11=2). Третім числом у цьому ряду буде 33 (33:11=3), четвертим - 44 (44:11=4) і т.д. Як бачимо, кожне наступне потрібне нам число можна отримати додаванням того числа, кратність якого нам потрібна:

Ось і відповідь на питання, що писати в тіло циклу: треба щоразу додавати те число, яке увів користувач, і виводити відповідь. І так 20 разів (кількість повторів циклу обумовлена умовою задачі).

Якщо позначимо число, яке ввів користувач як n1, а число, яке буде виводити програма як n2, то отримуємо такий алгоритм:

Розберемо роботу цього алгоритму на конкретних числах:

10.1 Двадцять кратних чисел
Якщо відкрити цю таблицю у новій вкладці, то там можна ввести своє число і побачити, як зміняться усі результати

Ну й, нарешті, сама програма:

n1 = int(input('Введіть початкове число: '))

n2 = n1  #записуємо у змінну n2 наше число, щоб його можна було вивести перший раз

for i in range(20):       #запуск лічильника на 20 повторів

    print(n2, end = ' ')  #виводимо перше число, ставимо після нього пробіл

    n2 += n1              #збільшуємо число n2 на n1 - отримуємо наступне 

А можна щось у цій програмі вдосконалити?

Дана програма, дійсно, містить недолік. Наприклад, якщо уважно роздивитися надану вище таблицю, то можна помітити, що на останньому 20 кроці роботи циклу програма обчислює наступне, 21-ше число, яке нам не потрібне і не буде виводитися. Чи можна зробити так, щоб цього не робити?

Для цього треба розібратися, чому так виходить. Уся справа в тому, що в тілі циклу останньою є команда n2:=n2+n1. От вона-то й "винна" у тому, що обчислюється зайве число. На останньому, 20-му кроці, останньою є команда, яка обчислює 21-ше число. Значить, треба просто зробити так, щоб останньою в тілі циклу була команда виведення результату. Просто поміняємо місцями команди в тілі циклу, перед "запуском" циклу додамо ще одну команду print(n2, end = ' '); і зменшимо кількість повторів тіла циклу (перше ж число нашого ряду вже виведене ще до старту циклічних обчислень):

n1 = int(input('Введіть початкове число: '))

n2 = n1

print(n2, end = ' ')

for i in range(19):

    n2 += n1

    print(n2, end = ' ')

Тепер уже робота програми організована більш раціонально, щоправда, у ній стало більше на 1 рядок. Так буває: у чомусь виграли, у чомусь програли... 🙄

Звісно, що хороше - ворог кращого, але про те, як зробити свою роботу ще кращою, слід думати завжди. І не тільки в програмуванні 😉

Чи існує інший спосіб розв'язання цієї задачі?

Наявність двох і, навіть, більше варіантів - це досить звичне явище. От і в цьому випадку інший спосіб написати програму для цього випадку існує. Якщо ми ще раз повернемося до першого прикладу, розглянутого як ілюстрація до цієї задачі, то побачимо там такий ряд чисел, кратних числу 11:

11 22 33 44 55 66 77 88 99 ...

Що являють собою ці числа? На першому місці стоїть число 11, на другому - 22 (22=11*2), на третьому - 33 (33=11*3), на четвертому - 44 (44=11*4) і т.д. Очевидно, що на двадцятому місці стоятиме число 11*20=220. Таким чином, маємо, що кожне наступне число можна отримати множенням початкового числа на його порядковий номер:

Оскільки номером по порядку в нашому циклі виступає лічильник і, значить. можемо його використати для обчислення наступного елемента нашого ряду чисел. Не забуваймо тільки, що у разі використання скороченої форми запису умови циклу з лічильником, відлік цього лічильника почнеться з НУЛЯ, а, отже, перший добуток буде рівним нулю. Щоб уникнути цього непорозуміння, доведеться використати повну форму умови циклу, в якому на друге місце (складова <stop>) поставити не 20, а 21 (пам'ятаєте, що <stop> - це значення лічильника, при якому виконання циклу ПРИПИНЯЄТЬСЯ?):

n1 = int(input('Введіть початкове число: '))

for i in range(1, 21, 1):

    n2 = n1 * i

    print(n2, end = ' ')

Тепер уже не тільки інший спосіб розв'язання, а й кількість рядків знову зменшилась, бо першим кроком циклу буде множення нашого початкового числа на 1, отже, перше число n1, з якого починається ряд,  автоматично буде виведене.

А шукати інший спосіб розв'язання задачі корисно завжди. І не тільки в програмуванні.

Завдання 31

Користувач вводить з клавіатури перше число діапазону, кількість потрібних чисел та інтервал, через які потрібно виводити числа. Вивести увесь діапазон чисел. 

Наприклад, користувач хоче вивести 8 чисел, перше з яких 3, а кожне наступне на 0,7 більше за попереднє. Що робить програма? Програма виводить ряд: 3 3,7 4,4 5,1 5,8 6,5 7,2 7,9. Все.

Як бачимо, ця програма схожа на попередню: перше число не n1, а якесь x, кількість чисел не 20, а n, а кожне наступне число отримуємо додаванням до попереднього не того ж таки числа n1, а деякого іншого (можливо й дробового!) числа h.

Спробуйте написати цю програму самостійно, спираючись на код до Завдання 30

x = float(input('Введіть перше число: '))

n = int(input('Введіть кількість чисел: '))

h = float(input('Задайте інтервал: '))

for i in range(n):

    print(x, end = ' ')

    x += h

От тепер, коли ми дізналися як знаходити усі числа, що утворюються за деяким правилом, можемо перейти до однієї з типових задач програмування, яка носить назву "цикл з накопиченням". Цикл з накопиченням характерний тим, що при черговому ви­конанні циклу нове значення змінної-результату буде залежати від зна­чення цієї ж змінної, визначеної на попередній ітерації тіла циклу.

Розглянемо приклад:

Завдання 32

Обчислити суму n чисел, починаючи з деякого числа x, якщо кожне наступне число більше за попереднє на y

Ця задача теж схожа на попередню. У ній так само потрібно за введеним з клавіатури першим числом, кількістю чисел в діапазоні й інтервалом обчислити усі числа діапазону. Тільки на цей раз їх потрібно не просто вивести на екран, а пододавати і вивести не самі ці числа, а їх суму. Так, з попереднім рядом, що був прикладом до Завдання 31, і який складається з 8-ми чисел, починається з числа 3 й має інтервал 0,7 потрібно виконати таке обчислення:

3 + 3,7 + 4,4 + 5,1 + 5,8 + 6,5 + 7,2 + 7,9 = 43,6

Відповідь 43,6 слід вивести на екран.

Зрозуміло, що ця задача має дві складові:

Як знайти числа ряду, ми уже знаємо. Дивимося в розв'язання Завдання 31 - там воно! От тільки незрозуміло, куди подіти уже знайдені числа нашого діапазону. Якщо вивести їх на екран, то як їх потім знову увести в програму? Команда input "уміє" читати тільки введене з клавіатури. Ну не набирати ж їх користувачу вручну заново!

Ще одним варіантом є "завести" собі стільки змінних, скільки чисел у ряді і при отриманні кожного наступного числа присвоювати нове значення наступній змінній.

Усе це було б добре, якби усе не було так погано! Те, що цей спосіб провальний, видно неозброєним оком. Кількість-то чисел ряду задає користувач програми! Звідки ми знаємо, скільки чисел йому наступного разу заманеться обчислювати? Скільки змінних створювати? Ну так, щоб на всі випадки вистачило! Сто? Тисячу? Мільйон? А не "задовбаємося" набирати мільйон змінних? До пенсії встигнемо?

Знову не той варіант! 😞

Для виходу з нашої безвиході є добра новина! Річ у тім, що УСІ комп'ютери й УСІ мови програмування придумали ЛЮДИ! Значить, у них - ЛЮДСЬКА ЛОГІКА! Тому, складаючи програму для комп'ютера, часто буває корисним задати собі питання: а як би я розв'язував/розв'язувала цю задачу, якби мені треба було виконати ці обчислення ВРУЧНУ?

А вручну ми б робили таке:

УРА! Ось воно рішення! Нам потрібна ще одна змінна, до якої ми будемо в циклі додавати кожне наступне знайдене число ряду. Після того як ми, як у коробку, "поскладаємо у цю змінну" усі наші числа, то в ній опиниться якраз те, що ми й шукали - сума усіх чисел ряду.

Позначимо нашу "коробочку", в якій будемо накопичувати суму, літерою s (бо "сума") і запишемо код програми:

Блок-схема алгоритму обчислення суми з накопиченням
Не забудьте. що при введенні дробових чисел потрібно ставити не європейську десяткову кому, а в американському форматі - крапку

Зверніть увагу на команду s=0 в рядку 6. Це обнулення "коробочки" зроблене для того, щоб у разі повторного запуску цієї програми нові числа нового ряду не додавалися до результатів попереднього обчислення суми.

Ще раз уважно перечитайте код програми й, переглядаючи демонстрацію, розберіться на конкретному прикладі з тим, як працює цей цикл:

Завдання 33

Геометричною прогресією називається послідовність чисел, в якій кожне наступне число отримується шляхом множення попереднього числа на один і той самий множник (його називають знаменником геометричної прогресії). Обчислити суму чисел, що є членами такої послідовності, якщо відоме перше число, кількість чисел та знаменник геометричної прогресії.

Приклад: якщо перше число в геометричній прогресії дорівнює 2, знаменник 3, а всього таких чисел 8, тоді потрібно обчислити суму чисел 2 6 18 54 162 486 1458 4374.

Ця програма повністю така ж, як і попередня і буде відрізнятися від неї лише ОДНИМ ОПЕРАТОРОМ! Здогадалися, яким?

x = float(input('Задайте перше число діапазону: '))

n = int(input('Введіть кількість чисел діапазону: '))

y = float(input('Задайте множник: '))

s = 0               #обнуляємо змінну, яка міститиме накопичувану суму

for i in range(n):  #задаємо цикл з n ітерацій

    s += x          #додаємо до суми поточне число

    x *= y          #обчислюємо наступне число МНОЖЕННЯМ - єдина відмінність!

print(s)            #виводимо накопичену суму

Згідно з однією давньою легендою, індійському цареві Шераму так сподобалася гра в шахи, що він вирішив щедро нагородити того, хто її придумав. Цар викликав до себе Сету (так за цією легендою звали винахідника гри в шахи) і запитав, яку ж винагороду той хотів би отримати. На це Сета відповів, що хотів би отримати винагороду пшеницею, причому пшеницю слід було порахувати таким чином: на першу клітинку шахової дошки покласти одну зернинку, на другу - дві, на третю - чотири і т.д. на кожну наступну клітинку класти удвічі більше, ніж на попередню і так до 64-ї.

До чого тут ця легенда? А до того, що увівши тепер умову цієї задачі (перше число  - 1, кількість чисел - 64, множник - 2) в щойно створену програму до Завдання 33 ви зможете за долі секунди розв'язати проблему, над якою усі придворні математики царя Шерама працювали усю ніч і дізнатися, скільки ж зерняток пшениці мав отримати винахідник шахів. А якщо ще й обчислите масу цієї кількості пшениці (є така одиниця вимірювання маси - гран: маса зернятка; 1 гран - це приблизно 64,8 міліграма), тоді зрозумієте, чому ця винагорода ніколи не могла бути видана.

ВИСНОВКИ

З цього уроку ви дізналися про те, що:

ДОМАШНЄ ЗАВДАННЯ

І рівень (на "6"):

Відомий тариф на перевезення одного пасажира в маршрутному таксі. Вивести у стовпчик вартість проїзду у маршрутному таксі для 1, 2, 3, ... , 10 пасажирів.

Підказка

Дивимося Завдання 30, враховуючи, що вартість проїзду двох пасажирів - це вартість проїзду одного, помножена на 2, вартість проїзду трьох - це вартість проїзду одного, помножена на 3 і т.д., а також те, що відповіді потрібно виводити в стовпчик (просто print, без end=' ').

ІІ рівень (на "11"):

Факторіалом деякого числа n (позначається n!) називають добуток усіх натуральних чисел від 1 до даного числа n, тобто, n!=1∙2∙3∙...∙n. Наприклад, факторіалом числа 5 є добуток 5!=1∙2∙3∙4∙5=120. Скласти програму для обчислення факторіала деякого, введеного користувачем, числа.

Підказка

Перше число в цьому ряду завжди одне й те саме - це число 1. Кількість чисел теж відома: для факторіала числа 5 таких чисел теж 5. Кожне наступне число ряду отримуємо додаванням одиниці до попереднього числа. На відміну від попередніх задач тут потрібно обчислювати не суму, а добуток. Словом, це Завдання 32 з дещо видозміненим тілом циклу і ще з одним уточненням, яке треба внести в рядок 10. Спробуйте самостійно здогадатися, яким, адже на це число потрібно буде множити, а тому подумайте, яким повинно бути значення цієї "коробочки" ДО ПОЧАТКУ роботи циклу.