Reputation: 465
This is related to this question: SAS macro variable change.
The code below explains the problem:
%macro test (arg=);
options mlogic mprint symbolgen;
array arraytwo [%EVAL(&arg+1)] _temporary_;
sum=0;
%do i = 1 %to %EVAL(&arg+1);
sum=sum+&i;
arraytwo[&i]=sum;
%end;
return=arraytwo[&arg+1];
%mend test;
/* This is ok */
data dat1;
%test(arg=9);
run;
data dat2;
input M;
cards;
5
6
7
;
run;
/* This give an error= A character operand was found in the %EVAL function or %IF condition where a numeric
operand is required. The condition was: M+1 */
data dat3;
set dat2;
%test(arg=M);
run;
So the question is why does it bug in the last test? Thanks.
Upvotes: 3
Views: 2096
Reputation: 4475
If you happen to be using SAS 9.2 or later you might want to look at proc fcmp to create a function to do this.
If you write it as a function instead of a macro, you can pass in data set variables that would resolve to numeric values - or pass numeric values directly. For example, try this code:
proc fcmp outlib=work.funcs.simple;
function sumloop(iter);
x=1;
do i=1 to iter+1;
x+i;
end;
return(x);
endsub;
run;
/* point to the location the function was saved in */
option cmplib=work.funcs;
data _null_;
input M;
y=sumloop(M); /* data set variable */
z=sumloop(9); /* static numeric value */
put M= @7 y= @14 z= @20 ;
cards;
1
2
3
4
5
6
7
8
9
;
run;
/* My log looks like this:
14 data _null_;
15 input M;
16 y=sumloop(M); /* data set variable */
17 z=sumloop(9); /* static numeric value */
18 put M= @7 y= @14 z= @20 ;
19 cards;
M=1 y=3 z=55
M=2 y=6 z=55
M=3 y=10 z=55
M=4 y=15 z=55
M=5 y=21 z=55
M=6 y=28 z=55
M=7 y=36 z=55
M=8 y=45 z=55
M=9 y=55 z=55
*/
Upvotes: 4
Reputation: 2529
I have to say I'm not entirely sure what you're trying to do; but does this give you the results you're looking for? The problem with your code above is the way you are trying to combine dataset variables and macro variables-- it isn't as easy to do as one might hope...
%macro test (argList=, totNumObs=);
%local arg;
%local j;
%local i;
%do j = 1 %to &totNumObs;
%let arg = %scan(&argList, &j);
array array&j [%EVAL(&arg+1)] _temporary_;
sum = 0;
%do i = 1 %to %EVAL(&arg+1);
sum = sum+&i;
array&j[&i] = sum;
%end;
return = array&j[&arg+1];
output;
%end;
%mend test;
data dat2;
input M;
cards;
5
6
7
;
run;
proc sql noprint;
select
count (*) into :numObs
from dat2 ;
select
M into :listofMs separated by ' '
from dat2
order by M;
quit;
options mlogic mprint symbolgen;
data dat3;
%test(argList= &listofMs, totNumObs= &numObs);
run;
proc print data= dat3;
run;
Upvotes: 2