русс | укр

Мови програмуванняВідео уроки php mysqlПаскальСіАсемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование


Linux Unix Алгоритмічні мови Архітектура мікроконтролерів Введення в розробку розподілених інформаційних систем Дискретна математика Інформаційне обслуговування користувачів Інформація та моделювання в управлінні виробництвом Комп'ютерна графіка Лекції


Функції


Дата додавання: 2014-11-28; переглядів: 858.


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

Поширені підпрограми, що вимагають повернення всього одного вихідного параметра, що є скаляром ( тобто, єдиним значенням, а не вектором або матрицею). У цих випадках замість підпрограми-процедури використовується підпрограма-функція, що повертає скалярний результат своєї роботи в основну програму. Тому для функції в її заголовку необхідно вказати тип результату, що вертається, а в тілі функції повинен бути присутнім хоча б один оператор присвоювання, у лівій частині якого записується ім'я функції:

Function Ім'я (Список формальних параметрів):Типрезультата;

{вище - заголовок підпрограми}

Var опису локальних змінних;

Begin

{Тіло функції}

Ім'я:=Вирази1;

End;

Тут Вирази1 повинне мати той же тип, що й зазначений у заголовку ТипРезультата, а оператор Ім'я:=Вирази1; не зобов'язано бути останнім у тілі функції. Оскільки результат виконання функції вертається в основну програму через її ім'я, то звертання до функції записується аналогічно стандартним функціям у вигляді операнда вирази, що стоїть праворуч від знака присвоювання:

Результат:=Вирази2;

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

Усі, сказане вище про узгодження формальних і фактичних параметрів, а також про параметри-значеннях і змінних, повною мірою ставиться й до функцій.

Фактично, стандартні підпрограми Паскаля також діляться на функції й процедури, залежно від способу їх виклику. Так, writeln ставиться до стандартних процедур, а sin – до функцій. Правда, деякі зі стандартних підпрограм мають змінне число параметрів, що заборонене користувацьким підпрограмам.

Зрозуміло, при використанні функцій ніхто не забороняє повертати більш одного значення через параметри-змінні, подібні тим, що ми вивчили для процедур. Можна сказати, що функції в Паскалі – це процедури, здатні повертати додаткове скалярне значення. У багатьох інших мовах програмування спеціального поділу на процедури й функції немає.

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

Процедура Функція
Викликається окремим оператором Викликається з вирази праворуч від знака присвоювання
Використовує параметри-значення й змінні Використовує параметри-значення й змінні, додатково доступний параметр-змінна з іменем, що збігаються з іменем функції

Напишемо й викличемо найпростішу функцію, що знаходить максимальний із двох своїх дійсних аргументів:

Function Max (a,b:real):real;

Begin

If a>b them Max:=a

Else Max:=b;

End;

Викликати цю функцію ми могли б так:

Var x,y,z,r,t:real;

. . .

Read (x,y,z);

r:=max(x,y); {Максимальне зі значень x,y записали в r}

t:=max(max(x,y),z); {Максимальне зі значень x,y,z записали в t}

Останній виклик ілюструє, що, як і стандартні функції, функції, написані програмістом, можуть викликатися з як завгодно складних виразів – за умови, що ми будемо дотримувати правил відповідності параметрів. Написану нами функцію max неважко було б реалізувати й у вигляді процедури:

Procedure Max (a,b:real; var c:real);

Begin

If a>b them c:=a

Else c:=b;

End;

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

Ми вже знайомі з оператором Halt;, що дозволяють аварійно (або просто з нескінченного циклу) завершити програму. Негайно завершити поточний блок, у тому числі й підпрограму-функцію або процедуру, дозволяє оператор Exit;.

 

Тепер приклади.

Пр. Використовуючи підпрограму, обчислити суму перших k членів ряду 1+1/n.

Сума ряду – це скаляр, природнім виглядає використання підпрограми-функції. Застосувавши відомі алгоритми, складемо програму:

function sum (k:integer):real;

var i:integer;

s:real;

begin

s:=0;

for i:=1 to k do s:=s+1/i;

sum:=s;

end;

 

var k:integer;

s:real;

begin

write ('Уведіть число кроків:');

readln (k);

s:=sum(k);

writeln ('Сума=',s:8:3);

end.

Зверніть увагу — незважаючи на те, що функція Sum обчислює єдину величину s, ми були б не має права написати в ній оператор for i:=1 to k do sum:=sum+1/i; - адже sum – це ім'я функції, і праворуч від знака присвоювання воно було б сприйняте як спроба функції sum викликати саму себе, причому, без дотримання правил відповідності параметрів. Тому нам знадобилася "проміжна" змінна s.

Проте, рекурсивні функції, що викликає самі себе, існують і будуть коротко розглянуті трохи нижче.

 

Пр. Обчислити значення вирази , де z(x)= sin 2x + ln |x|.

Очевидно, що повторне обчислення вирази z(x) з різними значеннями аргументу x неефективно, куди зручніше написати підпрограму-функцію, що вважає по формулі z(x)= sin 2x + ln |x| :

function z(x:real):real;

begin

z:=sin(2*x)+ln(abs(x));

end;

 

begin

write ('Відповідь=', (z(3)+2*sqr(z(5)))/(z(0.1)+1):6:2);

readln;

end.

Як видне із прикладу, використання функції дозволило виконати розрахунки єдиним оператором (з обліком того, що writeln "уміє" друкувати значення обчислених виразів).

 

На закінчення розділу скажемо кілька слів про рекурсію. Рекурсивними називають функції, здатні повторно викликати самі себе. З погляду програмування, у цьому немає нічого дивного – просто при повторному вході у функцію в програмному стеці створюється її нова копія й розрахунки виконується заново зі зміненим значенням параметра функції. Потім функція перевіряє значення параметра, при необхідності змінює його й знову повторно викликає сама себе. Зрозуміло, щоб уникнути зациклення, при деякім значенні параметра повинне бути передбачене завершення обчислювального процесу. Використання рекурсії доцільно скрізь, де розрахунки наступного значення деякої функції залежить від її попереднього значення. Так, класичний приклад на рекурсію – розрахунки факторіала (факторіал цілого позитивного числа n, позначуваний n!, дорівнює добутку всіх чисел від 1 до N включно). Використовуючи очевидну формулу n!=n*(n-1)!, напишемо наступну рекурсивну функцію:

Function Factorial (n:integer):longint;

begin

if n<2 then Factorial:=1

else Factorial:=n*Factorial(n-1);

end;

Тип функції longint використаний, тому що факторіал дуже швидко росте й уже 8!=40320, тобто, більше максимального значення типу integer. Ця функція, як неважко побачити, при значенні аргументу, меншому двох, повертає одиницю, а а якщо ні, то повертає свій аргумент n, помножений на факторіал від n-1. Нескладний тест функції міг би виглядати так:

begin

writeln ('10!=',Factorial(10));

end.

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

При написанні рекурсивних функцій слід ураховувати, що рекурсивні виклики досить швидко заповнюють стек і загрожують його переповненням. Тому основна проблема при написанні такої функції – відітнути свідомо зайві вкладені виклики. Для цього використовують додаткові перевірки умов, що визначають, чи доцільно поглиблювати далі поточний рівень вкладень.

 


<== попередня лекція | наступна лекція ==>
Процедури | Масиви як параметри підпрограми


Онлайн система числення Калькулятор онлайн звичайний Науковий калькулятор онлайн