четверг, 24 ноября 2016 г.

Використання власних функцій

Заняття 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)


     Наступного разу я розгляну у статті використання списків, які більш відомі як масиви. До зустрічі.