在 SAS 数据步骤中编写 Ackermann 函数
Writing the Ackermann function in a SAS data step
为了理解 SAS 中的递归编程,我曾多次尝试编写 two-argument 阿克曼函数的一个版本,但均未成功。
函数指出:
我只打算计算 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
依此类推 Ack(3,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;
如果您必须将它与数据集变量的值一起使用,那么您可以考虑使用 resolve() 函数。
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 class 实现
sasuser.examples.ackermanclass.scl
Class Ackerman extends sashelp.fsp.object.class;
compute: public method
m: num
n: num
return = num;
if m=0 then return n+1;
if m > 0 then do;
if n = 0 then return compute ( m-1, 1 );
if n > 0 then return compute ( m-1, compute ( m, n-1 ) );
throw _new_ SASHelp.Classes.SCLException ("Ackerman compute, invalid args: n=" || cats(n));
end;
throw _new_ SASHelp.Classes.SCLException ("Ackerman compute, invalid args: m=" || cats(m));
endmethod;
EndClass;
sasuser.examples.ackermantest.scl
init:
declare sasuser.examples.ackerman.class ackerman
= _new_ sasuser.examples.ackerman.class();
do m = 0 to 3;
do n = 0 to 3;
put m= n= 'result=' ackerman.compute(m,n);
end;
end;
return;
测试 AFA C=sasuser.examples.ackermantest.scl
m=0 n=0 result=1
m=0 n=1 result=2
m=0 n=2 result=3
m=0 n=3 result=4
m=1 n=0 result=2
m=1 n=1 result=3
m=1 n=2 result=4
m=1 n=3 result=5
m=2 n=0 result=3
m=2 n=1 result=5
m=2 n=2 result=7
m=2 n=3 result=9
m=3 n=0 result=5
m=3 n=1 result=13
m=3 n=2 result=29
m=3 n=3 result=61
这是使用递归的 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 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;
为了理解 SAS 中的递归编程,我曾多次尝试编写 two-argument 阿克曼函数的一个版本,但均未成功。
函数指出:
我只打算计算 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
依此类推 Ack(3,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;
如果您必须将它与数据集变量的值一起使用,那么您可以考虑使用 resolve() 函数。
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 class 实现
sasuser.examples.ackermanclass.scl
Class Ackerman extends sashelp.fsp.object.class;
compute: public method
m: num
n: num
return = num;
if m=0 then return n+1;
if m > 0 then do;
if n = 0 then return compute ( m-1, 1 );
if n > 0 then return compute ( m-1, compute ( m, n-1 ) );
throw _new_ SASHelp.Classes.SCLException ("Ackerman compute, invalid args: n=" || cats(n));
end;
throw _new_ SASHelp.Classes.SCLException ("Ackerman compute, invalid args: m=" || cats(m));
endmethod;
EndClass;
sasuser.examples.ackermantest.scl
init:
declare sasuser.examples.ackerman.class ackerman
= _new_ sasuser.examples.ackerman.class();
do m = 0 to 3;
do n = 0 to 3;
put m= n= 'result=' ackerman.compute(m,n);
end;
end;
return;
测试 AFA C=sasuser.examples.ackermantest.scl
m=0 n=0 result=1
m=0 n=1 result=2
m=0 n=2 result=3
m=0 n=3 result=4
m=1 n=0 result=2
m=1 n=1 result=3
m=1 n=2 result=4
m=1 n=3 result=5
m=2 n=0 result=3
m=2 n=1 result=5
m=2 n=2 result=7
m=2 n=3 result=9
m=3 n=0 result=5
m=3 n=1 result=13
m=3 n=2 result=29
m=3 n=3 result=61
这是使用递归的 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 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;