Calls

CS 162
Introduction to Computer Science
Chapter 4
Function Calls
Herbert G. Mayer, PSU
Status 11/9/2014
1
Syllabus
 C++ Functions
 Calls
 Varying Number of Actuals
 Nested Calls
 Recursion
2
C++ Functions
 Functions are prime building blocks for C++
programs that render them readable and
maintainable; named logical modules
 A function is a contained module, identified by its
name
 That name can be called, in which case the function
executes, regardless of where in the program it
appears textually
 It has been designed to enclose some logically
contained and coherent purpose. That purpose is
fulfilled by the call
 It is possible to re-use a function at a different place,
call it from that different place
3
C++ Functions
 In the function declaration we refer to them as
formal parameters
 The call provides compatible actual parameters
 Actual and formal must pairwise match in type and
correspond by position: type compatibulity
 Like in C, it is allowed to pass a smaller number of
actual parameters than formally specified
 A void function solely performs the action of the
statements enclosed in the { and } pair
 A true function, however, may return a value to its
place of call; the type is specified in the definition
4
Varying Number of Actuals
 Define void function foo( int a, int b)
with 2 formal parameters
 If a is 0, a message stating so is printed, and
parameter b is skipped, i.e. there will be no
corresponding actual
 But if a is greater than 0, the value of the
second, b is printed
 Note: Some compilers do not allow by
default
5
Implement Varying Number of Actuals
#include <iostream.h>
void foo( int a, int b )
{ // foo
if ( a ) {
cout << “parameter b = “ << b << endl;
}else{
cout << “no value for b is passed” << endl;
} //end if
} //end foo
int main( void )
{ // main
foo( 0 );
foo( 1, 2014 );
return 0;
} //end main
6
Discuss Varying Number of Actuals
 It would be an error, if a smaller than
specified number of actual is passed, and
yet such a formal parameter would be
referenced that has not actually been
provided
 In such cases, random garbage on the runtime stack is mis-interpreted as formal ‘b’
 Generally a serious error 
7
Function min( a, b )
 Define int function min() that returns the
smaller of 2 passed actual parameters
 Though trivial, we extend this to allow the
selection of the smallest of 3 or more
candidate values
 One way to achieve this is to nest some of
the actual parameters via further function
calls
8
Implement min( a, b )
#include <iostream.h>
int min( int a, int b )
{ // min
return ( a < b ) : a ? b;
} //end foo
int main( void )
{ // main
cout << “smaller of -12, 12:”
<< min( -12, 12 ) << endl;
cout << “smallest of 88, -9, 100:”
<< min( min( 88, -9 ), 100 ) << endl;
cout << “smallest of 200, 300, 400:”
<< min( 200, min( 300, 400 ) ) << endl;
cout << “smallest of 10, -99, 100, -888:”
<< min( min( 10, -99), min( 10, -888 ) ) << endl;
return 0;
} //end main
9
Discuss min( a, b ) => min( a, b, c, d )
 The point here is to demonstrate nested
function calls
 Allows virtual extension of a function to a
more complex one, without having to code it
 See 2 samples of min( a, b, c ) with 3
candidates
 And 1 sample of selecting the smallest of 4
candidates, and yet we have implemented
just a simple min( a, b ) function
10
Definition of Recursive Algorithm
An algorithms is recursive, if it is partly defined by simpler versions of itself [1]

A recursive program is the implementation of a recursive algorithm

What is the key problem for a programmer, using a language that is non-recursive (e.g.
standard Fortran) if the algorithm to be implemented is recursive? --See later!
What then are the other parts of a recursive algorithm?

Correct recursive algorithm requires a starting point, formally known as “base case”

Base case could be multiple steps
Recursive algorithm a() uses a base case as starting point for computation, plus the
actual function body, including some recursive use of a()
Recursive body can be indirectly recursive through intermediate function

a()-> b()-> a() – through intermediate function b()
Primitive examples are the factorial( n ) function; or Fibonacci( n ), for non-negative
arguments n; Fibo( n ) shown here:

Base case 1:
Fibo(0) = 0

Base case 2:
Fibo(1) = 1

Recursive Definition:
Fibo( n ) for n > 1 = Fibo( n-1 ) + Fibo( n-2 )
11
Function Fibo( n )
 Define int function Fibo() that returns the Fibonacci
number of its passed, unsigned, integer argument n
 Though trivial to code iteratively, we use recursion
to compute Fibo( n )
 We saw the definition for recursion earlier, so we
know:


Check for a termination condition; that is the “partly
defined” condition
Check that the recursive call proceeds with a simpler
argument than the original; that is the “simpler version” of
the recursion definition
 Let us ignore that integers could be negative, and
assume non-negative, original arguments to Fibo()
12
Implement Fibo( n )
. . .
int Fibo( unsigned n )
{ // Fibo
if ( 0 == n ) {
return 0;
}else if ( 1 == n ) {
return 1;
}else{
return Fibo( n – 1 ) + Fibo( n – 2 );
} //end Fibo
int main( void )
{ // main
cout << “Fibo( 8 ) = “ << Fibo( 8 ) << endl;
return 0;
} //end main
13
Discuss Fibo( n )
 Demonstrate recursive function calls
 But the recursive function is defined in
simpler versions of itself, hence we cannot
call Fibo( n ) any longer in the body
 So: Fibo( n-1 ), and also Fibo( n-2 ) are valid
possibilities
 Also, the recursive function is partly defined
via a call to itself; i.e. there are other parts
 Those parts are the checks for termination
early: is the argument already 0 or 1, if so,
we know and return the result.
 In all other cases: recurse!
14
Q-Sequence, Definition
Q-Sequence defined by Douglas Hofstadter in [1] as a function q( n ) for
positive integers n > 0
Base case n = 1: q(1) = 1
Base case n = 2: q(2) = 1
Recursive definition of q(n), for positive n > 2
q( n ) = q( n – q( n - 1 ) ) + q( n – q( n - 2 ) )
Q-Sequence reminds us of Fibonacci( n ) function, but with surprising
difference in the type of result:
By contract, the function results of fibonacci( n ) are monotonically
increasing with increasing argument
Results of q( n ) are non-monotonic!
Note # of calls: calls(q( 40 )) = 1,137,454,741
15
Q-Sequence, Coded in C
#define MAX 100
// arbitrary limit; never reached!!!!
int calls;
// will be initialized each time
int q( int arg )
{ // q
calls++;
//
if ( arg <= 2 ) {
return 1;
//
}else{
//
return q( arg } // end if
} // end q
track another call
base case
now recurse!
q( arg-1 ) ) + q( arg - q( arg-2 ) );
// note: printf() allowed in C++
void main()
{ // main
for( int i = 1; i < MAX; i++ ) {
calls = 0;
// initially no calls yet
printf( "Q(%2d) = %3d, #calls = %10d\n", i, q(i), calls );
} // end for
} // end main
16
Q-Sequence Results
Q( 1)
Q( 2)
Q( 3)
Q( 4)
Q( 5)
Q( 6)
Q( 7)
Q( 8)
Q( 9)
Q(10)
Q(11)
=
=
=
=
=
=
=
=
=
=
=
1,
1,
2,
3,
3,
4,
5,
5,
6,
6,
6,
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
=
=
=
=
=
=
=
=
=
=
=
1
1
5
13
25
49
93
161
281
481
813
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
14,
16,
16,
16,
16,
20,
17,
17,
20,
21,
19,
20,
22,
21,
22,
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
#calls
=
1341433
=
2174493
=
3521137
=
5700281
=
9229053
=
14941993
=
24182797
=
39137473
=
63354153
= 102525697
= 165896537
= 268460333
= 434429737
= 702952137
= 1137454741
. . .
Q(26)
Q(27)
Q(28)
Q(29)
Q(30)
Q(31)
Q(32)
Q(33)
Q(34)
Q(35)
Q(36)
Q(37)
Q(38)
Q(39)
Q(40)
. . . Will never reach Q(100) in your life time 
17
Ackermann Definition
Ackermann a( m, n ) is defined as a function of two nonnegative integers m and n
Base case 1: a( 0, n ) = n + 1
Base case 2: a( m, 0 ) = a( m - 1, 1 )
Recursive definition of a( m, n ), m, n > 0
a( m, n ) = a( m - 1, a( m, n - 1 ) )
Ackermann complexity grows awfully fast; e.g. a(4,2)
is an integer number with 19,729 decimal digits;
greater than the national US debt!
18
Ackermann Definition
Students, code now in C++, and volunteers shows result
on white-board:
Base case 1: a( 0, n ) = n + 1
Base case 2: a( m, 0 ) = a( m - 1, 1 )
Recursive definition of a( m, n ), m, n > 0
a( m, n ) = a( m - 1, a( m, n - 1 ) )
19
Ackermann Coded in C
unsigned a( unsigned m, unsigned n )
{ // a
calls++;
if ( 0 == m ) {
return n + 1;
}else if ( 0 == n ) {
return a( m - 1, 1 );
}else{
return a( m-1, a( m, n-1 ) );
} // end if
} // end q
//
//
//
//
//
//
//
global unsigned
note operand order
first base case
m > 0
other base case
m > 0, n > 0
recurse!
void main()
{ // main
for( int i = 0; i < MAX; i++ ) {
printf( "\nFor m = %d\n", i );
for( int j = 0; j < MAX; j++ ) {
calls = 0;
printf( "a(%1d,%1d) = %10u, calls = %12u\n",
i, j, a( i, j ), calls );
} // end for
} // end for
} // end main
20
Ackermann Results
For m = 0
a(0,0) =
...
1, calls =
1
For m = 1
...
a(1,7) =
9, calls =
16
For m = 2
a(2,0) =
a(2,1) =
a(2,2) =
a(2,3) =
a(2,4) =
a(2,5) =
a(2,6) =
a(2,7) =
3, calls =
5, calls =
7, calls =
9, calls =
11, calls =
13, calls =
15, calls =
17, calls =
5
14
27
44
65
90
119
152
For m = 3
a(3,0) =
5, calls =
15
a(3,1) =
13, calls =
106
a(3,2) =
29, calls =
541
a(3,3) =
61, calls =
2432
a(3,4) =
125, calls = 10307
a(3,5) =
253, calls = 42438
a(3,6) =
509, calls = 172233
a(3,7) = 1021, calls = 693964
For m = 4
a(4,0) =
13, calls =
107
don’t even dream about computing a(4,2)  or higher!
21
Recursion vs. Iteration
• Iteration is expressed in programming
languages by loops; e.g. for-, while-, do-, or
repeat loops
• These are readable and efficient methods for
expressing iteration, but are not strictly
necessary
• Recursion can replace iteration; yet for some
people this seems counter-intuitive
• Neophytes are sometimes unused to
recursion; yet recursion can be as intuitive
as simple iteration 
22
Replace Iteration via Recursion
• Using only functions, called recursively
• Plus arithmetic increment/decrement
operators ++ -- and unary minus –
• And conventional relational operators > >=
!= etc.
• All other operators are dis-allowed in this
experiment, i.e. no + - * / % ** etc.
23
Recursion vs. Iteration: add()
// return a + b without + operation!
int add( int a, int b )
{ // add
if ( 0 == b ) {
return a;
}else if ( b < 0 ) {
return add( --a, ++b );
}else{
return add( ++a, --b );
} //end if
} //end add
24
Recursion vs. Iteration: sub()
// return a – b; no dyadic – operation
int sub( int a, int b )
{ // sub
return add( a, -b );
} //end sub
25
Recursion vs. Iteration: mult()
// return a * b, no * but add()
int mult( int a, int b )
{ // mult
if ( 0 == b ) {
return 0;
}else if ( 1 == b ) {
return a;
}else if ( b < 0 ) {
return -mult( a, -b );
}else{
// b > 0
return add( a, mult( a, --b ) );
} //end if
} //end mult
26
Recursion vs. Iteration: expo()
// return a ** b, no ** op in C++; requires mult( int, int )
int expo( int a, int b )
{ // expo
if ( 0 == a ) {
if ( 0 == b ) {
cout << ”undefined value0^0” << endl;
}else if ( b < 0 ) {
cout << “0 to <0 power undefined” << endl;
} //end if
return 0;
}else if ( 0 == b ) {
return 1;
}else if ( 1 == a ) {
return 1;
}else if ( -1 == a ) {
return b % 2 ? -1 : 1;
}else if ( b < 0 ) {
return 0;
}else{
return mult( expo( a, --b ), a );
} //end if
} //end expo
27