DATA Step, Macro, Functions and more

How to compare variables with floating point values within a macro?

Accepted Solution Solved
Reply
New Contributor
Posts: 4
Accepted Solution

How to compare variables with floating point values within a macro?

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
Solution
‎08-08-2012 10:58 AM
Super Contributor
Posts: 282

Re: How to compare variables with floating point values within a macro?

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


All Replies
Super Contributor
Posts: 1,636

Re: How to compare variables with floating point values within a macro?

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

Valued Guide
Posts: 797

Re: How to compare variables with floating point values within a macro?

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.

Super Contributor
Posts: 282

Re: How to compare variables with floating point values within a macro?

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.

Super Contributor
Posts: 282

Re: How to compare variables with floating point values within a macro?

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.

New Contributor
Posts: 4

Re: How to compare variables with floating point values within a macro?

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)

???

Super Contributor
Posts: 282

Re: How to compare variables with floating point values within a macro?

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.

New Contributor
Posts: 4

Re: How to compare variables with floating point values within a macro?

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?

Super Contributor
Posts: 1,636

Re: How to compare variables with floating point values within a macro?

if you insist not using &w then changing

b=&w

to

%let b=&w;

New Contributor
Posts: 4

Re: How to compare variables with floating point values within a macro?

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 !

Solution
‎08-08-2012 10:58 AM
Super Contributor
Posts: 282

Re: How to compare variables with floating point values within a macro?

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.

Valued Guide
Posts: 797

Re: How to compare variables with floating point values within a macro?

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;


Super User
Posts: 5,085

Re: How to compare variables with floating point values within a macro?

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.

☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

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