9.4. Функции
Функция, будучи аналогичной процедуре, отличается от нее тем, что результатом ее выполнения является только одно значение, которое возвращается в точку вызова. Второе отличие состоит в том, что имя функции может использоваться в выражении в качестве операнда.
Для возврата в главную программу вычисленного функцией значения в теле функции необходимо предусмотреть хотя бы один оператор присваивания, в котором слева от символа ’:=’ ставится имя функции, а справа - выражение, вычисляющее её значение. Таких операторов в теле функции может быть и несколько, но при каждом обращении к ней должен выполняться только один.
Тип значения, вычисляемого функцией, задаётся в её заголовке, имеющем вид
function имя_функции (список формальных параметров):t;,
где t - тип вычисляемого значения.
Пример 9.4
Вычисление площади треугольника (см. пример 9.2) оформить в виде функции.
function tr1(ab, bc, ca : real ) : real ;
var
p : real ;
begin
p:=(ab + bc + ca) / 2;
tr1:=sqrt(p * (p - ab) * (p - bc) * (p - ca))
end;
Обращение к функции аналогично обращению к процедуре, но самостоятельным оператором не является. В качестве операторов вызова функции используют операторы, содержащие выражения, например, оператор присваивания, условный оператор или процедуру вывода. При этом обращение к функции должно входить в выражение в качестве его операнда.
П ример 9.5
Используя функцию tr1 (пример 9.4), решить задачу, приведённую в примере 9.3.
program example95;
var
a, b, c, d, e, f, s : real;
function tr1(ab, bc, ca : real ):real;
var
p : real;
begin
p:=(ab + bc + ca) / 2;
tr1:=sqrt (p * (p - ab) * (p - bc) * (p - ca))
end;
begin
readln (a, b, c, d, e, f);
s:=tr1 (a, b, c) + tr1 (a, d, e) + tr1(b, e, f) + tr1(c, f, d);
writeln ('s= ', s:10:2)
end.
Оператором вызова служит оператор присваивания. Операндами его арифметического выражения являются четыре обращения к функции.
И процедуры и функции в качестве формальных параметров могут использовать как параметры-значения, так и параметры-переменные. Однако, использование параметров-переменных зачастую приводит к нежелательным побочным эффектам, связанным с их изменением в процессе выполнения подпрограммы.
В такой ситуации возрастает вероятность появления трудноуловимых ошибок. Поэтому опытные программисты рекомендуют всюду, где это возможно, в качестве формальных параметров использовать параметры-значения.
9.5. Рекурсия
Под рекурсией (от лат. recursio - возвращение) понимают способ организации вычислительного процесса, который позволяет находить n-ный член какой-либо последовательности (чаще всего числовой), используя для этого один или несколько её предыдущих членов. Например, широко известный ряд чисел Фибоначчи 1, 1, 2, 3, 5, 8, ... для n > 2 вычисляется по рекуррентной формуле:
F(n) = F(n - 1) + F(n - 2)
Другим примером использования рекурсии является вычисление факториала
Для решения задачи, в которой используется рекурсия, необходимо, чтобы процедура или функция могла бы вызвать саму себя. TurboPascal такую возможность предоставляет.
Пример 9.6
Используя приведённую выше рекуррентную формулу, вычислить n!
program example96;
var
n, f : integer;
function factorial (m : integer) : integer ;
begin
if m=0 then factorial := 1
else factorial := factorial (m - 1) * m
end;
begin
readln (n); f:=fac (n);
write ('факториал ',n:2, '=',f:2)
end.
Замечание. Поскольку n! растет очень быстро, то при n > 7 полученные значения превышают максимально возможное значение типа integer (32767), поэтому рекомендуется n! считать как longint.
Программа содержит два обращения к функции factorial - одно в операторе вызова в главной программе, другое - в операторе присваивания в теле самой функции. Из главной программы функция вызывается один раз. При этом ей передаётся значение фактического параметра n. Для определённости допустим, что n = 3. Итак, функция начинает выполняться со значением формального параметра m = 3. Поскольку m 0, должна выполниться ветвь else оператора if, т.е. оператор присваивания factorial := factorial(2)*3. Но правая часть этого оператора содержит обращение к функции factorial, поэтому функция обратится сама к себе с параметром равным 2. Это в свою очередь приведёт к новому обращению к функции с фактическим параметром равным 1.
Таким образом, однократный вызов функции из главной программы приводит к цепочке последовательных незавершенных вызовов этой же функции самой себя. При этом в каждом последующем вызове используется значение формального параметра на 1 меньшее того, что использовалось в предыдущем. Все эти значения запоминаются в разных ячейках памяти. Так будет продолжаться до тех пор, пока значение функции не станет полностью определённым, что произойдёт при значении параметра m = 0. В этом случае будет выполнен оператор factorial := 1, после чего процесс вычисления факториала начнёт «раскручиваться» в обратную сторону, последовательно выполняя операторы:
factorial(1):=factorial (0)*1
factorial (2):=factorial (1)*2
factorial (3):=factorial (2)*3