Search code examples
sascomputation-theory

Writing the Ackermann function in a SAS data step


In my quest to understand recursive programming in SAS, I have tried, unsuccessfully many times, to write a version of a two-argument Ackermann function.

The function states that:

I was only going to calculate m & n for values ranging from 0 - 3, as values of m >= 4 cause the returned values to become large very rapidly.

I was shooting for a relatively simple output; something like:

Ack(0,0) = 1
Ack(0,1) = 2
Ack(0,2) = 3
Ack(0,3) = 4
Ack(1,0) = 2
Ack(1,1) = 3

And so on to Ack(3,3) = 61

I was unable to find any reference online to someone doing this in SAS. So, if someone could help me with this, I would really appreciate it!

Thanks!


Solution

  • It is difficult to do recursion in normal SAS code. But it is easy in macro code.

    %macro a(m,n);
    %if %sysfunc(verify(&m.&n,0123456789)) %then %do;
      %put WARNING: Invalid input to macro &sysmacroname.. Use only non-negative integers.;
      .
    %end;
    %else %if (&m=0) %then %eval(&n+1);
    %else %if (&n=0) %then %a(%eval(&m-1),1);
    %else %a(%eval(&m-1),%a(&m,%eval(&n-1)));
    %mend a;
    

    If you must use it with the values of dataset variables then you might consider using the resolve() function.

    data testa;
      do i=0 to 3; do j=0 to 3;
        a=input(resolve(cats('%a(',i,',',j,')')),32.);
        output;
      end;end;
    run;
    proc print; run;
    

    Results

    Obs    i    j     a
    
      1    0    0     1
      2    0    1     2
      3    0    2     3
      4    0    3     4
      5    1    0     2
      6    1    1     3
      7    1    2     4
      8    1    3     5
      9    2    0     3
     10    2    1     5
     11    2    2     7
     12    2    3     9
     13    3    0     5
     14    3    1    13
     15    3    2    29
     16    3    3    61
    

    Of course if you are only ever going to use arguments from 0 to 3 then perhaps you just need to use an array lookup instead.

    data testb;
      array _a(0:3,0:3) _temporary_
    (1 2 3 4
     2 3 4 5
     3 5 7 9
     5 13 29 61
    );
     do i=0 to 3; do j=0 to 3; a=_a(i,j); output; end; end;
    run;