- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi
I am trying to create this simple macro to compute an expression after doing a floating point number comparison ...
%macro calc_val(x,y);
%if &x < &y %then <expression 1>;
%else <expression 2>;
%mend calc_val;
/* initiate macros */
%let b = 23.6;
%calc_val(32.5, &b)
run;
The code is running but it is not doing it properly.
In the above example, the SAS log file is saying
SYMBOLGEN: Macro variable X resolves to 32.5
SYMBOLGEN: Macro variable Y resolves to B
MLOGIC(CALC_VAL): %IF condition &x < &y is TRUE
Hence it is computing expression 1 instead it should have gone to compute expression 2.
Where am I going wrong?
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Does this mean I need to use &w only?
That is all you need to call the macro function.
Why is SAS not able to pass on the value stored in variable 'b' to the next macro?
Because the macros are processed first then data steps are processed afterwards.
Do you know of any other work around?
As SAS is working as designed, I would not consider a workaround is necessary.
You can still assign the value &w to b if you need to use b as a data step variable, but you'll still need to use &w in the macro function call.
NB. Please also follow Astounding's recommendation about the use of %sysevalf()
Regards,
Amir.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I ran your code and it looks fine:
%macro calc_val(x,y);
%if &x < &y %then %put &x < &y;
%else %put &x ge &y;
%mend calc_val;
/* initiate macros */
%let b = 23.6;
%calc_val(32.5, &b)
log file:
17 %macro calc_val(x,y);
18
19 %if &x < &y %then %put &x < &y;
20
21 %else %put &x ge &y;
22
23 %mend calc_val;
24
25
26
27 /* initiate macros */
28
29 %let b = 23.6;
30
31 %calc_val(32.5, &b)
32.5 ge 23.6
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I can't reproduce your results. Running your code with arguments you specified, I get expression 2 (i.e. &x < &y is NOT true), as expected.
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set
Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets
--------------------------
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
When I try the following code based on yours it goes down the %else branch and puts out "False".
%macro calc_val(x,y);
%if &x < &y %then
%put True;
%else
%put False;
%mend calc_val;
/* initiate macros */
%let b = 23.6;
%calc_val(32.5, &b)
What do you get when you run the above?
Regards,
Amir.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
With the options:
options symbolgen mlogic;
I see the following extract in the log:
SYMBOLGEN: Macro variable B resolves to 23.6
MLOGIC(CALC_VAL): Parameter X has value 32.5
MLOGIC(CALC_VAL): Parameter Y has value 23.6
SYMBOLGEN: Macro variable X resolves to 32.5
SYMBOLGEN: Macro variable Y resolves to 23.6
MLOGIC(CALC_VAL): %IF condition &x < &y is FALSE
MLOGIC(CALC_VAL): %PUT False
The only way I can reproduce your result is by invoking the macro function without using the ampersand (&) before the second argument (b):
%calc_val(32.5, b)
which gives:
MLOGIC(CALC_VAL): Parameter X has value 32.5
MLOGIC(CALC_VAL): Parameter Y has value b
SYMBOLGEN: Macro variable X resolves to 32.5
SYMBOLGEN: Macro variable Y resolves to b
MLOGIC(CALC_VAL): %IF condition &x < &y is TRUE
Regards,
Amir.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi
Thanks all.
Actually, I am still getting an issue. Will it make a difference if the value of b is actually getting calcaulted within a data step of another macro.
I am also calling the the original macro from within this data step.
So, effectively I have ..
%macro calc_val(x,y);
%if &x < &y %then <expression 1>;
%else <expression 2>;
%mend calc_val;
%macro mac_1(w);
data qwer;
....
b = &w;
%calc_val(32.5, b)
run;
%mend mac_1;
/* initiate macros */
%let c = 23.5;
%mac_1(&c)
???
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Yes it will make a difference, as it did do in my last post when I showed I get the same result as you when I invoke the macro function without using an ampersand (&) before the second argument (b). The macro function will compare the value "32.5" (without the quotes) with the value "b" (without the quotes.)
Try changing:
%calc_val(32.5, b)
to:
%calc_val(32.5, &w)
Regards,
Amir.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Amir, Thanks.
It does work.
Does this mean I need to use &w only?
Why is SAS not able to pass on the value stored in variable 'b' to the next macro?
Do you know of any other work around?
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
if you insist not using &w then changing
b=&w
to
%let b=&w;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Linlin
I can't use that.
Recall that 'b=&w' statement is placed within the data step of the macro.
Essentially b will become a variable for the data table qwer !
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Does this mean I need to use &w only?
That is all you need to call the macro function.
Why is SAS not able to pass on the value stored in variable 'b' to the next macro?
Because the macros are processed first then data steps are processed afterwards.
Do you know of any other work around?
As SAS is working as designed, I would not consider a workaround is necessary.
You can still assign the value &w to b if you need to use b as a data step variable, but you'll still need to use &w in the macro function call.
NB. Please also follow Astounding's recommendation about the use of %sysevalf()
Regards,
Amir.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
I don't know why you would not use &W as the parameter in your macro call, since its value is unchanged for your entire data step.
But you may be looking for the RESOLVE function, which provides a means to delay resolution of a macro call until data step execution - i..e it's a means of having the data in a given record influence what the macro returns. As in:
%macro t(arg);
%if &arg=2 %then 2;
%else 3;
%mend t;
data have;
do a=1 to 2;output; end;
run;
data _null_;
set have;
b=a*resolve(cats('%t(',a,')'));
put a= b=;
run;
But this will probably generate a significant performance hit, which you can test by multiplying data set HAVE to, say 100,000 observations. Then run the above data _null_ step (take out the put statement), and compare its speed to this data _null_ step:
data _null_;
set have;
if a=1 then b=a*%t(1);
else b=a*%t(2);
run;
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set
Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets
--------------------------
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
The issue you are looking at is that macro language is making a character comparison, not a numeric comparison. Decimal points are not interpreted as numbers by macro language. So if you changed your example to use 203.5 instead of 23.5, you would get the unexpected results.
The solution is easy. Macro language contains a function that supports floating point arithmetic. Change your comparison to:
%if %sysevalf ( &x < &y ) %then %put True;
That should take care of it.
Good luck.