PROC FCMP routines can
be recursive. Recursion is a problem-solving technique that reduces
a problem to a smaller one that is simpler to solve and then combines
the results of the simpler solution to form a complete solution. A
recursive function is a function that calls itself, either directly
or indirectly.
Each time a
routine is called, space for the local variables is pushed on the
call stack. The space on the call stack ensures independence of local
variables for each call. When the routine returns, the space allocated
on the call stack is removed, freeing the space used by local variables.
Recursion relies on the call stack to store progress toward a complete
solution.
When a routine calls
itself, both the calling routine and the routine that is being called
must have their own set of local variables for intermediate results.
If the calling routine was able to modify the local variables of the
routine that is being called, it would be difficult to program a recursive
solution. A call stack ensures the independence of local variables
for each call.
In the following example,
the ALLPERMK routine in PROC FCMP has two arguments,
n and
k,
and writes all
P(n, k)
= n! /(n - k)!
permutations that contain exactly
k out
of the
n elements. The elements
are represented as binary values (0, 1). The function ALLPERMK calls
the recursive function PERMK to traverse the entire solution space
and output only the items that match a particular filter.
proc fcmp outlib=sasuser.funcs.math;
subroutine allpermk(n, k);
array scratch[1] / nosymbols;
call dynamic_array(scratch, n);
call permk(n, k, scratch, 1, 0);
endsub;
subroutine permk(n, k, scratch[*], m, i);
outargs scratch;
if m–1 = n then do;
if i = k then
put scratch[*];
end;
else do;
scratch[m] = 1;
call permk(n, k, scratch, m+1, i+1);
scratch[m] = 0;
call permk(n, k, scratch, m+1, i);
end;
endsub;
run;
quit;
options cmplib=sasuser.funcs;
data _null_;
call allpermk(5, 3);
run;
Log Output from Recursion Example
1 1 1 0 0
1 1 0 1 0
1 1 0 0 1
1 0 1 1 0
1 0 1 0 1
1 0 0 1 1
0 1 1 1 0
0 1 1 0 1
0 1 0 1 1
0 0 1 1 1
This program uses the
/NOSYMBOLS option in the ARRAY statement to create an array without
a variable for each array element. A /NOSYMBOLS array can be accessed
only with an array reference,
scratch[m]
,
and is equivalent to a DATA step _temporary_ array. A /NOSYMBOLS array
uses less memory than a regular array because no space is allocated
for variables. ALLPERMK also uses PROC FCMP dynamic arrays.