The SAS Macro Language is a text based language. There are no numbers or numeric variables. This problem does not exist in the Data Step, because numbers and characters are two separate things. However, that is not the case in the Macro Facility. Therefore, arithmetic and logical operations are not as straight forward. That is why we need evaluations function as the %Eval Macro Function. Consider the small example below. Here, a evaluates to the string 1+2. If I want to do the arithmetic operation of adding the two numbers, I have to use an evaluation function such as the %Eval Function.
%let a = 1+2; %let b = %eval(1+2); %put &=a &=b;
In this post, I will focus on the %Eval Macro Function and provide examples for you to explore and understand it.
A Few Examples
The %Eval Function takes a character argument, converts it to an arithmetic or logical expression, evaluates it and converts the result back to text. The %Eval Function treats integers as numbers. As you see in the example above, 2 and 1 were treated as integers and successfully added. However, it does not handle floating point arithmetic. This means that it can not handle adding 1.5 to 1 as you see in the first example. The two following lines verify that the mere presence of a period in a numeric expression makes %Eval interpret it as a character value. This causes an error, because it failed to add a character value to a number.
We just learned that the %Eval Function treats numbers with periods as character. Consequently, we must be careful when it comes to logical comparisons. Consider the line that creates the macro variable d. Here, I use the %Eval Function to evaluate whether 10.0 is greater than 2.0. This is easy right? Of course it is. Remember, that the %Eval Function treats both 10.0 and 2.0 as character values because of the period. Therefore, a character comparison takes place from left to right. In a character comparison, SAS uses the same sort sequence as Proc Sort. This means that ‘1’ comes before ‘2’. Therefore, the %Eval Function evaluates d to 0. Which is not obvious at first.
Finally, caution must be taken when using a division operator. In the last example, I divide 3 by 2 and save the evaluated result in the macro variable e. 3 divided by 2 is 1.5. However, the %Eval Macro Function truncates the result to an integer. Meaning that the returned value is 1.
%let a = %eval(1+1.5); /* Error */ %let b = %eval(1+1.0); /* Error */ %let c = %eval(1+1.); /* Error */ %let d = %eval(10.0 > 2.0); /* No error. But d evaluates to 0. */ %let e = %eval(3/2); /* SAS truncates e to 1 */ %put &=a &=b &=c &=d &=e;
Implicit %Eval Macro Calls
Above, we learn how to use the %Eval Function explicitly and what pitfalls we must avoid. However, when writing macro logic, you call the %Eval Function more than you are probably aware of implicitly. Consider the code below. The expression 1+1=2 is an logical (and arithmetic) expression and must be treated as such. Therefore, an evaluation function must be called.
%macro a; %if 1+1=2 %then %put one plus one equals two!; %mend; %a;
This means that the code above looks like this behind the scenes. In fact this is true for all %IF-%THEN/%ELSE Macro Statements.
%macro b; %if %eval(1+1=2) %then %put one plus one equals two!; %mend; %b;
Since we know that an implicit %Eval Function call takes place in all %IF-%THEN/%ELSE Macro Statements, the same caution must be taken as described earlier when it comes to comparing non-integers. Consider the code below. Once again, the implicit %Eval Function considers both 10.0 and 2.0 as character values and concludes that 10.0 is less than 2.0. Run the code and verify for yourself.
%macro c; %if 10.0 > 2.0 %then %do; %put 10.0 is greater than 2.0!; %end; %else %do; %put 10.0 is less than 2.0!; %end; %mend; %c;
The implicit SAS %Eval call is not limited to conditional macro logic. In fact, it takes place in all macro functions and macro statements in which an logical or arithmetic expression exists. It even takes place in macro text functions that accept a length or position argument such as%Scan and %Substr. The iterative logic in the macro below contains four implicit macro calls.
%macro iter; %do i = 1 %to 10 %by 2; %put &i; %end; %mend; %iter;
Here, I write out all the implicit calls. There is one call for each number and a call to iterate the SAS macro variable i.
%macro iter2; %do i = %eval(1) %to %eval(10) %by %eval(2); %put &i; /* %let i = %eval(&i + 2); Implicit */ %end; %mend; %iter2;
This post is devoted to the SAS %Eval Function. We look at both explicit and implicit use of the function. We learn that the %Eval Function deals with integers only. Furthermore, we see examples of common pitfalls such as numbers being treated as characters, division and more. Also, we look at the implicit %Eval Function calls. These take place in all macro statements that exploit arithmetic and logical expressions, such as %IF-%THEN/%ELSE Macro Statements and iterative macro logic and
You can download the entire code from this post here.