Hi everyone,
I'm perplexed by a situation I've encountered and I'm wondering if anyone can explain to me the inner SAS workings behind this.
I have a list of macros variables that I am scrolling through and subjecting to macro conditional logic. Something like this:
%let var1=0.1;
%let var2=0.5;
%let var3=1.5;
%let var4= ;
%let var5=0;
%macro q;
%if 0 < &&var&i < 1 %then %put &&var&i is between 0 and 1;
%else %put &&var&i is not between 0 and 1;
%mend q;
%q
My issue is this: the macro variable that is null (in this case, &var4) seems to resolve this condition as TRUE! This seems strange to me! I understand that a null value of a macro variable is not the same as a missing value of a data step variable, but I'm still not sure why this should resolve as being 0<var<1. I have tried other conditions, such as %IF &&VAR&I > 1 and these do NOT resolve as TRUE.
I have managed to get this code running fine using solutions to check for macro variables with null values prior to my conditional logic step, but my questions is WHY does &var4 resolve as being between 0 and 1? Can anyone explain to me the SAS workings behind this? Like I said, the code is working find with some work-arounds, but I am curious to know the reason behind it.
Thanks in advance for any insight you can provide!
Ashley
Ashley,
There are two issues you will run into. The first one explains the results for &VAR4.
%if &a < &b < & c %then %do;
In macro language, expressions resolve from left to right. This statement operates as if you had added parentheses:
%if (&a < &b) < &c %then %do;
Macro makes the first comparison, and replaces true comparisons with 1 and false comparisons with 0. In your case, when &VAR4 is null, null is less then 0 so the first comparison is false. The second comparison then becomes: 0 < 1 which is, of course, true.
The second issue you will encounter has to do with decimal points. When macro language makes comparisons, it applies the %EVAL function. %EVAL interprets decimal points as character strings. Thus this comparison would also be true:
%if 39 < 4.0 %then %do;
As others have noted, %SYSEVALF can perform decimal fraction arithmatic. This comparison would be false:
%if %sysevalf (39 < 4.0) %then %do;
Good luck.
This
0 < &&var&i < 1
type of logic doesn't work in macro world, you need to specify it as 0 < &&var&i and &&var&i < 1
There's an explanation of why somewhere on here but I don't recall
I think it resolves as 0<null = false then false<1 which is true rather than as vari between 0 and 1.
Be careful when to use "0 < &&var&i < 1 ", in Macro, it will be interpreted as 0 < (&&var&i < 1). So anything that is less then 1 will be true, including those negative numbers. Instead, breaking it up seems to be the safer way:
&&var&i >0 and &&var&i < 1
Haikuo
From the looks of those macro variable decimal values, I'm thinking you need to get %SYSEVALF involved. Or better still don't use macro for this.
Absolutely.
"You must use the %SYSEVALF function to evaluate logical expressions containing floating-point or missing values."
You could do something as follows:
data _null_;
format x 9.3 y $4. z $50.;
do i=1 to 5 ;
x = symget('var'||left(i));
y = 'var'||left(i);
if ( 0 < x < 1 ) then do ;
z = y || " is between 0 and 1";
put z;
end ;
else do ;
z = y || " is not between 0 and 1";
put z;
end;
output;
end ;
run;
Ashley,
There are two issues you will run into. The first one explains the results for &VAR4.
%if &a < &b < & c %then %do;
In macro language, expressions resolve from left to right. This statement operates as if you had added parentheses:
%if (&a < &b) < &c %then %do;
Macro makes the first comparison, and replaces true comparisons with 1 and false comparisons with 0. In your case, when &VAR4 is null, null is less then 0 so the first comparison is false. The second comparison then becomes: 0 < 1 which is, of course, true.
The second issue you will encounter has to do with decimal points. When macro language makes comparisons, it applies the %EVAL function. %EVAL interprets decimal points as character strings. Thus this comparison would also be true:
%if 39 < 4.0 %then %do;
As others have noted, %SYSEVALF can perform decimal fraction arithmatic. This comparison would be false:
%if %sysevalf (39 < 4.0) %then %do;
Good luck.
Bravo for the correct answer!
Thank you, Astounding, for putting this so eloquently! The left-to-right logic makes perfect sense to me and i can now see the problem with this comparison!
P.S. thanks to all for the %SYSEVALF tip as well... i had actually sort of simplified/anonymized my code to post this question and hence the code i listed would not actually have worked without %SYSEVALF, but my real code was fine (other than that darn null macro variable!). thank you regardless for the feedback on that too.
Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.