在SAS数据步骤中写入Ackermann函数

在SAS数据步骤中写入Ackermann函数,sas,computation-theory,Sas,Computation Theory,为了理解SAS中的递归编程,我曾多次尝试编写一个双参数Ackermann函数的版本,但都没有成功 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; 该函数声明: 我只打算计算0-3范围内的值的m&n,因为m>=4的值会导致返回值迅速变大 我拍摄的是一个相对简单的输出;比如:

为了理解SAS中的递归编程,我曾多次尝试编写一个双参数Ackermann函数的版本,但都没有成功

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;
该函数声明:

我只打算计算0-3范围内的值的m&n,因为m>=4的值会导致返回值迅速变大

我拍摄的是一个相对简单的输出;比如:

Ack(0,0) = 1
Ack(0,1) = 2
Ack(0,2) = 3
Ack(0,3) = 4
Ack(1,0) = 2
Ack(1,1) = 3
依此类推至Ack3,3=61

我无法在网上找到在SAS中执行此操作的人的任何参考资料。所以,如果有人能帮我,我会非常感激


谢谢

在普通SAS代码中进行递归是困难的。但在宏代码中很容易实现

%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;

如果必须使用DataSet变量的值,则可以考虑使用Selp函数。

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;
结果

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
当然,如果您只打算使用从0到3的参数,那么您可能只需要使用数组查找

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;

在普通SAS代码中很难进行递归。但在宏代码中很容易实现

%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;

如果必须使用DataSet变量的值,则可以考虑使用Selp函数。

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;
结果

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
当然,如果您只打算使用从0到3的参数,那么您可能只需要使用数组查找

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;

下面是一个SAS/AF类实现

sasuser.examples.ackermanclass.scl

sasuser.examples.ackermantest.scl

使用AFA C=sasuser.examples.ackermantest.scl进行测试


下面是一个SAS/AF类实现

sasuser.examples.ackermanclass.scl

sasuser.examples.ackermantest.scl

使用AFA C=sasuser.examples.ackermantest.scl进行测试


下面是使用递归的Proc DS2示例:

proc ds2;
  data _null_;
    method ackerman(int m, int n) returns int;
      if m=0 then return n+1;

      if m > 0 then do;
        if n = 0 then return ackerman ( m-1, 1 );
        if n > 0 then return ackerman ( m-1, ackerman ( m, n-1 ) );

        return -1;
      end;

      return -1;
    end;

    method init();
      declare int m n result;
      do m = 0 to 3;
      do n = 0 to 3;
        result = ackerman(m,n);
        put m= n= result=;
      end;
      end;
    end;
  enddata;
  run;

quit;

下面是使用递归的Proc DS2示例:

proc ds2;
  data _null_;
    method ackerman(int m, int n) returns int;
      if m=0 then return n+1;

      if m > 0 then do;
        if n = 0 then return ackerman ( m-1, 1 );
        if n > 0 then return ackerman ( m-1, ackerman ( m, n-1 ) );

        return -1;
      end;

      return -1;
    end;

    method init();
      declare int m n result;
      do m = 0 to 3;
      do n = 0 to 3;
        result = ackerman(m,n);
        put m= n= result=;
      end;
      end;
    end;
  enddata;
  run;

quit;
过程fcmp实施:

/* Define */
proc fcmp outlib=work.funcs.math;
function ackerman(m, n);
  if m = 0 then return(n + 1);
  else if n = 0 then return(ackerman(m - 1, 1));
  else return(ackerman(m - 1, ackerman(m, n - 1)));
endsub;
run;
quit;

/*Test*/
option cmplib = work.funcs;
proc fcmp;
  out = ackerman(3,2);
  put "Testing Function Call";
  put "ackerman(3,2) returns:" out;
quit;
过程fcmp实施:

/* Define */
proc fcmp outlib=work.funcs.math;
function ackerman(m, n);
  if m = 0 then return(n + 1);
  else if n = 0 then return(ackerman(m - 1, 1));
  else return(ackerman(m - 1, ackerman(m, n - 1)));
endsub;
run;
quit;

/*Test*/
option cmplib = work.funcs;
proc fcmp;
  out = ackerman(3,2);
  put "Testing Function Call";
  put "ackerman(3,2) returns:" out;
quit;

请共享您迄今为止尝试过的代码,也许有人可以帮助您使其工作。请共享您迄今为止尝试过的代码,也许有人可以帮助您使其工作。出于某种原因,mine开始返回从1,1观测obs 6开始的缺失值。确保使用%EVAL传递减去的值,而不仅仅是文本1-1。我同意。我希望自己能看到一个PROC FCMP解决方案。出于某种原因,我的解决方案开始返回从1,1观察obs 6开始的缺失值。确保使用%EVAL传递减去的值,而不仅仅是文本1-1。我同意。我希望自己能看到一个PROC FCMP解决方案。