BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Bapan
Calcite | Level 5

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?

1 ACCEPTED SOLUTION

Accepted Solutions
Amir
PROC Star

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.

View solution in original post

12 REPLIES 12
Linlin
Lapis Lazuli | Level 10

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

mkeintz
PROC Star

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

--------------------------
Amir
PROC Star

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.

Amir
PROC Star

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.

Bapan
Calcite | Level 5

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)

???

Amir
PROC Star

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.

Bapan
Calcite | Level 5

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?

Linlin
Lapis Lazuli | Level 10

if you insist not using &w then changing

b=&w

to

%let b=&w;

Bapan
Calcite | Level 5

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 !

Amir
PROC Star

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.

mkeintz
PROC Star

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

--------------------------
Astounding
PROC Star

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.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 12 replies
  • 4670 views
  • 10 likes
  • 5 in conversation