Notes 10: Functions


We have used many of MATLAB's functions. We can create our own functions as well. There are many advantages to organizing our operations within a function.

We will examine two approaches for defining functions: anonymous functions and stored functions.


Anonymous Functions

General syntax uses a format
fhandle = @(arglist) expr

As a concrete example, here is an anonymous function that computes the volume of a cylinder with a known height and radius.

cylinder = @(height, radius) pi * radius^2 * height;
After defining this function, we may call it as
v = cylinder(5, 3);   % returns 141.37

limitations


Stored Functions

While an anonymous function can be called from elsewhere within the file, it cannot be reused from other files. To make a function for more general use, it must be named and stored in an m-file based upon that name.

As an example, here is a function that computes the volume of a cylinder, given the height and radius.

function volume = cylinder(height, radius)
% function to compute the volume of a cylinder
% Usage:  volume = cylinder(height, radius)
  base = pi * radius^2;
  volume = base * height;        % the final answer
With this file in the current directory, it can be called from elsewhere using the syntax cylinder(h, r) for parameters h and r.

Returning multiple values

function [area, volume]  = cylinder(height, radius)
% function to compute the surface area and volume of a cylinder
% Usage:  [area, volume] = cylinder(height, radius)
  base = pi * radius^2;
  volume = base * height;                        % the second result
  area = 2 * pi * radius * height + 2 * base;    % the first result

The caller can retrieve both values using whatever variable names they want.

[a v] = cylinder(5, 3);
The caller can also choose to accept only some of the return values, but in that case, the number of returned values will be selected from left to right. It does not matter what variable name is used.
v = cylinder(5, 3);     % WILL BE THE AREA

Being aware of the number of arguments sent by caller

We can determine the number of parameters passed in with the keyword nargin.
function volume = cylinder(height, radius)
% function to compute the volume of a cylinder
% Usage:  volume = cylinder(height, radius)
%
% If not specified, radius is assumed to be 1        
  if nargin == 1
    radius = 1;                  % default value for second parameter
  end
  base = pi * radius^2;
  volume = base * height;        % the final answer

Being aware of the number of return values being caputred by caller

We can determine the number of captured return values, with the keyword nargout. We can use this knowledge to avoid unnecessary work.
function [area, volume]  = cylinder(height, radius)
% function to compute the surface area and volume of a cylinder
% Usage:  [area, volume] = cylinder(height, radius)
%
% If not specified, radius is assumed to be 1        
  if nargin == 1
    radius = 1;                  % default value for second parameter
  end
  base = pi * radius^2;
  area = 2 * pi * radius * height + 2 * base;    % the first result
  if nargout == 2
    volume = base * height;                      % the second result
  end

Writing vectorized functions

What if we wanted the above to work for a vector of heights and a vector of radius?
function [area, volume]  = cylinder(height, radius)
% function to compute the surface area and volume of a cylinder
% Usage:  [area, volume] = cylinder(height, radius)
%
% If parameters are vectors of equal length, or if one parameter is a
% scalar and the other is a vector, this returns a corresponding
% vector of areas and a vector of volumes.
%
% If not specified, radius is assumed to be 1        
  if nargin == 1
    radius = 1;                 % default value for second parameter
  end
  base = pi .* radius.^2;
  area = 2 .* pi .* radius .* height + 2 .* base;    % the first result
  if nargout == 2
    volume = base .* height;                         % the second result
  end

Subfunctions

You can define several functions in the same m-file, with the first one being the publically available one, and the others being used privately to support the first.

Case Study: Finding the Maximum Iteratively

Given a vector, we have discussed the basic algorithm for finding the maximum, by keep track of the maximum thus far while iterating through the vector.

Question: how many different elements qualify as being the maximum thus far during that process?

Goal: Develop a function peaks(v) that returns the number of elements that have value surpassing all previous elements in the vector. For example, peaks([5 1 8 3 8 11 10]) should return 3, as the first element, the third element and the sixth elements are new maximums (we do not count the fifth, because that value 8 did not surpass the previously visited maximum of 8).

Goal: Rewrite the function so that it can provide a second return value, which is a vector of indices achieving those peaks (akin to the second return value of the built-in max function). Thus peaks([5 1 8 3 8 11 10]) should return the pair [ 3 [1 3 6] ].