I have a SAS program which is generating SAS programs, and I want to conditionally use %include; that is, if the %include file exists, then %include it. This code demonstrates how.
* SAS conditional %include ;
* See also http://www.sascommunity.org/wiki/Conditionally_Executing_Global_Statements ;
data _null_;
file "c:\temp\a.txt";
put "a = 1;";
run;
data _null_;
file "c:\temp\b.txt";
put "b = 1;";
run;
%let include_file=c:\temp\a.txt;
%let include_file=c:\temp\c.txt;
%let include_file=c:\temp\b.txt;
data Work.test;
%sysfunc(ifc(%sysfunc(fileexist("&include_file")),
%include "&include_file";, %put File "&include_file" not found.;));
run;
proc print data=Work.test;
run;
Wednesday, December 18, 2013
Saturday, December 7, 2013
SAS: Looping thru a macro variable
Source code:
%macro doit(FOREACH=);
%local i j ;
%let j = 1 ;
%do %while(%scan(&FOREACH,&j) ne ) ;
%let i = %scan(&FOREACH,&j) ;
%put &FOREACH &j &i;
%let j = %eval(&j+1) ;
%end ;
%mend doit;
%doit(); * none ;
%doit(FOREACH=A); * one only, no parenthesis ;
%doit(FOREACH=(B)); * one only, with parenthesis ;
%doit(FOREACH=(C,D)); * two, comma separated, with parenthesis ;
%doit(FOREACH=(E F G)); * three, space separated, with parenthesis ;
Output from log:
125 %macro doit(FOREACH=);
126 %local i j ;
127 %let j = 1 ;
128 %do %while(%scan(&FOREACH,&j) ne ) ;
129 %let i = %scan(&FOREACH,&j)
130 %put &FOREACH &j &i;
131 %let j = %eval(&j+1) ;
132 %end ;
133 %mend doit;
134
135 %doit(); * none ;
136 %doit(FOREACH=A); * one only, no parenthesis ;
A 1 A
137 %doit(FOREACH=(B)); * one only, with parenthesis ;
(B) 1 B
138 %doit(FOREACH=(C,D)); * two, comma separated, with parenthesis ;
(C,D) 1 C
(C,D) 2 D
139 %doit(FOREACH=(E F G)); * three, space separated, with parenthesis ;
(E F G) 1 E
(E F G) 2 F
(E F G) 3 G
%macro doit(FOREACH=);
%local i j ;
%let j = 1 ;
%do %while(%scan(&FOREACH,&j) ne ) ;
%let i = %scan(&FOREACH,&j) ;
%put &FOREACH &j &i;
%let j = %eval(&j+1) ;
%end ;
%mend doit;
%doit(); * none ;
%doit(FOREACH=A); * one only, no parenthesis ;
%doit(FOREACH=(B)); * one only, with parenthesis ;
%doit(FOREACH=(C,D)); * two, comma separated, with parenthesis ;
%doit(FOREACH=(E F G)); * three, space separated, with parenthesis ;
Output from log:
125 %macro doit(FOREACH=);
126 %local i j ;
127 %let j = 1 ;
128 %do %while(%scan(&FOREACH,&j) ne ) ;
129 %let i = %scan(&FOREACH,&j)
130 %put &FOREACH &j &i;
131 %let j = %eval(&j+1) ;
132 %end ;
133 %mend doit;
134
135 %doit(); * none ;
136 %doit(FOREACH=A); * one only, no parenthesis ;
A 1 A
137 %doit(FOREACH=(B)); * one only, with parenthesis ;
(B) 1 B
138 %doit(FOREACH=(C,D)); * two, comma separated, with parenthesis ;
(C,D) 1 C
(C,D) 2 D
139 %doit(FOREACH=(E F G)); * three, space separated, with parenthesis ;
(E F G) 1 E
(E F G) 2 F
(E F G) 3 G
Friday, December 6, 2013
SAS: Floating point hell
I grew up on COBOL and mainframe Assembler. I loved packed decimal numbers because you always knew what you had. I HATE floating point numbers. I first stumbled upon this issue accidentally while learning C. The same issue exists in Java. And SAS.
I don't have time to elaborate right now. So I just want to capture the problem. Here is the SAS log. compare variables (e and f), (c and h), and (b and g). In particular, note my use of +1.E-10. Warning ... +1.E-11 gives different results.
1 data _null_;
2 a = 400.4444;
3 i = 4;
4 b = int(a * 10 ** i) / (10 ** i);
5 c = (a = b);
6 d = a * 10 ** i;
7 e = int(a * 10 ** i);
8 f = int(a * 10 ** i + 1.E-10);
9 g = int(a * 10 ** i + 1.E-10) / (10 ** i);
10 h = (a = g);
11 put a= i= b= c= d= e= f= g= h=;
12 run;
a=400.4444 i=4 b=400.4443 c=0 d=4004444 e=4004443 f=4004444 g=400.4444 h=1
I don't have time to elaborate right now. So I just want to capture the problem. Here is the SAS log. compare variables (e and f), (c and h), and (b and g). In particular, note my use of +1.E-10. Warning ... +1.E-11 gives different results.
1 data _null_;
2 a = 400.4444;
3 i = 4;
4 b = int(a * 10 ** i) / (10 ** i);
5 c = (a = b);
6 d = a * 10 ** i;
7 e = int(a * 10 ** i);
8 f = int(a * 10 ** i + 1.E-10);
9 g = int(a * 10 ** i + 1.E-10) / (10 ** i);
10 h = (a = g);
11 put a= i= b= c= d= e= f= g= h=;
12 run;
a=400.4444 i=4 b=400.4443 c=0 d=4004444 e=4004443 f=4004444 g=400.4444 h=1
Tuesday, December 3, 2013
SAS: Temporary arrays
Spent way too much time last night trying to determine why a program was taking too long to run. The time to run increased exponentially -- rather than linearly -- as more records were processed. I determined that it was too much reliance on symget and symput. When I used a temporary array instead, the program ran very quickly.
The following statement will create an array of numeric variables. Key points with temporary arrays:
Note how I was able to initialize all entries to zero.
array used [&_NVARS] _temporary_ (&_NVARS * 0);
Here I check the value of an element in the array:
if (used[&i] = 0) then do;
Here I set the value of an element in the array:
used[save_i] = 1;
The following statement will create an array of numeric variables. Key points with temporary arrays:
- You must specify the size with a numeric constant (or, as I did here, with a macro variable which evaluates to a numeric constant.)
- Temporary arrays are automatically retained.
- Temporary arrays are not written to the output data set.
Note how I was able to initialize all entries to zero.
array used [&_NVARS] _temporary_ (&_NVARS * 0);
Here I check the value of an element in the array:
if (used[&i] = 0) then do;
Here I set the value of an element in the array:
used[save_i] = 1;
Subscribe to:
Posts (Atom)