Заняття 6
На цьому занятті я розгляну створення власних функцій,
які використовуватимуться у програмах.
Нагадаю, що мова PYTHON є
функціональною, тобто використовує для роботи з даними функції. До цього часу
ми використовували стандартні функції, наприклад, int(), input(), print(), abs(), range(), map() тощо. Як видно із запису, всі вони після свого ім’я мають
дужки, в яких записується їх аргумент чи аргументи, тобто ті величини, для яких
визначається функція (якщо аргумент відсутній, то для функції береться той, що
за замовчуванням). При звертанні до функції у програмний код підставляється її
значення, наприклад, при виконанні запису
a=abs(b)
у змінну а записується значення модуля числа b.
Саме наявність великої кількості стандартних функцій
зробило цю мову програмування зручною до використання і навчання. Крім цього є
можливість підключення цілих модулів, кожен з яких містить від декількох до
кількох десятків різноманітних функцій. Підключення цих модулів буде розглянуто
пізніше, бо вони не входять до шкільної програми, але можуть використовуватися
в олімпіадних завданнях. Але яка б не була кількість стандартних функцій завжди
знайдеться та, яка потрібна до конкретної задачі, але вона не належить до них.
Наприклад, для знаходження площі опуклого багатокутника шляхом розбивання його
на трикутники з відомими сторонами, приводить до того, що потрібно
використовувати формулу Герона кілька разів. Якщо буде відповідна функція, яка
б за відомими трьома сторонами обчислюватиме площу трикутника, то вона значно
полегшить розв’язання
цієї задачі. До того ж використання функцій розбиває велику задачу на менші
підзадачі, які розв’язуватимуть вже функції. Взагалі, використання функцій приводить до кращого
розуміння ходу її розв’язку і «читання» програмного коду, що є дуже важливим фактором майбутнього
програміста, який буде працювати в команді.
Функцію
до використання у програмі потрібно написати, причому у будь-якому місці
програми, але до місця її виклику. Розглянемо написання функції Geron:
def Geron(a,b,c):
p=(a+b+c)/2
s=(p*(p-a)*(p-b)*(p-c))**0.5
return s
Перший рядок – це заголовок
(назва) функції, що містить у дужках аргументи (довжини сторін трикутника).Починається рядок зі слова def. В
кінці рядка ставиться двокрапка, а всі наступні рядки, що належать до функції,
зміщені праворуч.
Другий рядок містить обчислення
півпериметра трикутника, а третій – обчислення площі трикутника.
Четвертий рядок надає функції
значення s (площі).
Використаємо цю функції для
розв’язання наступної задачі. У одному рядку дано 5 натуральних чисел: сторони чотирикутнка
і довжина діагоналі, проведеної з вершини, спільної до перших двох сторін, до
вершини, спільної для третьої і четвертої. Знайти площу паралелограма (див. рисунок).
Весь програмний код матиме
такий вигляд:
def
Geron(a,b,c):
p=(a+b+c)/2
s=(p*(p-a)*(p-b)*(p-c))**0.5
return s
a,b,c,d,m=map(int,input().split())
s=Geron(a,m,d)+Geron(b,m,c)
print(s)
Кількість функцій, що можуть
використовуватися в програмі необмежена, причому з однієї функції може
викликатися інша. Якщо функція викликає саму себе, то вона називається
рекурсивною, а сам спосіб такого виклику – рекурсією. Найпростіший приклад
рекурсії є обчислення факторіалу n! (де n– невід’ємне число). Нагадаю, що n!=1∙2∙3∙…∙(n-1)∙n, або n!= (n-1)!∙n
Запишемо програму, яка для
даного числа визначає його факторіал
def fact(x):
if x==1:
return 1
else:
return fact(x-1)*x
n=int(input())
print(fact(n))
У рекурсивній функції повинна бути прописана
умова виходу з рекурсії (в нашому випадку при х=0). Поки не досягнута умова
виходу, значення функції набуває значення, яке береться з наступного значення
функції при іншому аргументі. Розглянемо покроково виконання цієї програми при n=4.
Після зчитування змінної n одразу
викликається функція виведення значення print(), аргументом
якої є значення функції fact(). Функція fact()
викликається перший раз із аргументом 4, тобто значення змінної х у функції
набуває значення 4. Пройшовши перевірку умови, значення цієї функції повинне
набути значення fact(3)*4, але значення fact(3) ще треба
обчислити, тому знову викликається ця сама функція, але вже з аргументом 3.
Після перевірки умови значення функції стане рівним fact(2)*3, тобто fact(3)= fact(2)*3, а fact(4)= fact(2)*3*4.
Наступний виклик функції відбувається з аргументом 1, тобто fact(2)= fact(1)*2 або fact(4)= fact(1)*2*3*4. Останній крок завершує виклик функції
(перериває рекурсію) і замість fact(1) виводить 1. Глибина рекурсії в даному випадку
становить 4, бо стільки разів викликається функція. Для людини цей процес важко
втримати в голові, а для комп’ютера просто, та і записується програма не досить
складно.
Ще одним із важливих прикладів використання
рекурсії є знаходження найбільшого спільного дільника (НСД) двох чисел за
алгоритмом Евкліда. Дійсно, якщо число с
є дільником чисел а і b, то він є дільником і їх різниці, тому НСД(а, b)= НСД(а, a-b) або НСД(а, b)= НСД(а, a % b). Якщо перший аргумент більший за другий, то можна
записати так: НСД(а, b)= НСД(b, a
%
b). Так щоразу значення аргументів будуть зменшуватися,
поки другий із них не стане дорівнювати 0. Отже, перший аргумент і буде
відповіддю. Тому функція буде мати такий вигляд:
def nsd(a,b):
if b!=0:
return nsd(b, a%b)
else:
return
а
Розглянемо кілька прикладів.
Приклад 1.
Знайти периметр багатокутника, заданого
координатами своїх вершин. У першому рядку дано натуральне число n(n<100). У наступних n рядках дано по два цілих числа – координати наступної
вершини багатокутника.
Вивести одне дійсне число,
округлене до сотих, – периметр багатокутника.
Вхід Вихід
4 19.79
-2 4
2 6
3 3
0 -2
def dist(x1,y1,x2,y2): # опис функції з ім’ям dist
return ((x1-x2)**2+(y1-y2)**2)**0.5 # обчислення функції
n=int(input()) #
зчитування кількості вершин
x1,y1=map(int,input().split()) # зчитування координат першої вершини
x0=x1 #
запам’ятовуємо під іншими змінними
y0=y1 #
p=0.0 # початкове значення периметру в дійсному типі
for i in range(n-1): #запуск циклу
для решти n-1 вершин
x2,y2=map(int,input().split()) # зчитування координат
p+=dist(x1,y1,x2,y2) # збільшення периметру на значення функції
x1=x2 # тепер друга координата стане першою для наступної
вершини
y1=y2 #
p+=dist(x1,y1,x0,y0) #додавання до периметру відстані між останньою вершиною і
першою
print(round(p,2)) #
виведення округленого до 2 знаків після коми значення периметра
Приклад 2.
Знайти найменше
спільне кратне (НСК) двох чисел. У двох рядках дано по одному натуральному
числу. Вивести одне натуральне число – НСК цих чисел.
Вхід Вихід
6 24
8
Скористаємося відомим співвідношенням
a*b=НСД(a,b)*НСК(a,b).
def nsd(a,b):
if b!=0:
return nsd(b, a%b)
else:
return a
x=int(input())
y=int(input())
print(x*y//nsd(x,y))
Приклад 3.
Опуклий п’ятикутник заданий
координатами своїх вершин. Знайти його площу. У п’ятьох рядках дано по два
дійсних числа – координати вершин п’ятикутника. Вивести значення площі
п’ятикутника з точністю до тисячних.
Вхід Вихід
-2 4 68.985
-4 0.9
0.42 -7.83
5.5 -0.34
2.34 5.3
Приклад 4.
Чотири бігуни бігають по колу
довжиною 100 м. Перший пробігає одне коло за а секунд, другий – за b секунд, третій – за с секунд, а четвертий – за d секунд. Всі
четверо починають бігти одночасно і не змінюють свою швидкість. Скільки метрів
пробіжить перший спортсмен, коли вони знову зустрінуться всі в точці старту?
У одному рядку через пробіл
дано 4 натуральних числа, що не менші за 10 і не більші за 100, – час, за яких
пробігає одне коло кожен спортсмен. Вивести одне натуральне число – відповідь
на задачу.
Вхід Вихід
10 20 25 50 1000
Пояснення прикладу: бігуни
зустрінуться в точці старту через 100 секунд, бо за цей час перший спортсмен пробіжить
рівно 10 кіл, другий – 5, третій – 4, а четвертий – 2. Тому перший спортсмен
пробіжить 10*100=1000 метрів.
def nsd(a,b):
if b!=0:
return nsd(b, a%b)
else:
return a
def nsk(a,b):
return a*b//nsd(a,b)
a,b,c,d=map(int,input().split())
s=nsk(nsk(nsk(a,b),c),d) # час, за який одночасно досягнуть
точки старту
print(s//a*100)
Наступного разу я розгляну у
статті використання списків, які більш відомі як масиви. До зустрічі.