Assigning a macro a macro value

Accepted Solution Solved
Reply
Occasional Contributor
Posts: 9
Accepted Solution

Assigning a macro a macro value

Hi,

I want to write a macro to run a model multiple times, each time setting the seed to a randomly selected value greater than 1. Right now my code looks something like this:

 

%macro RandBetween(min, max);
(&min + floor((1+&max-&min)*rand("uniform")))
%mend;

%macro DoLoop;
%DO j = 1 %TO 2 ;
%LET x = %RandBetween(1,50);
%LET Seed = %EVAL(&x+&j);

proc ... data=... ;

...

seed &seed;

run;

%END;
%MEND DoLoop;
%DoLoop;

 

However there is an issue assigning x a macro value. Any ideas how to assign a macro a random value?

Thanks!


Accepted Solutions
Solution
‎09-15-2017 07:10 AM
Super User
Posts: 8,590

Re: Assigning a macro a macro value

Posted in reply to aoifeoneill

When you do

%LET x = %RandBetween(1,50);

The macro call is resolved to

%LET x = (1 + floor((1+50-1)*rand("uniform")));

So that x will now contain the text string

(1 + floor((1+50-1)*rand("uniform")))
%LET Seed = %EVAL(&x+&j);

will then resolve to

%LET Seed = %EVAL((1 + floor((1+50-1)*rand("uniform")))+1);

(for &j=1) where the macro processor can't resolve floor and rand (as they are not macro functions), and will throw an error because of non-numeric data.

If you want to create a value, I suggest to use a data _null_ step:

%macro RandBetween(min, max);
(&min + floor((1+&max-&min)*rand("uniform")))
%mend;

%macro DoLoop;
%DO j = 1 %TO 2 ;
data _null_;
x = %RandBetween(1,50);
call symput('Seed',put(x+&j,best.));
run;

proc ... data=... ;

...

seed &seed;

run;

%END;
%MEND DoLoop;
%DoLoop;

You also have to question if macro randbetween is necessary at all.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers

View solution in original post


All Replies
Solution
‎09-15-2017 07:10 AM
Super User
Posts: 8,590

Re: Assigning a macro a macro value

Posted in reply to aoifeoneill

When you do

%LET x = %RandBetween(1,50);

The macro call is resolved to

%LET x = (1 + floor((1+50-1)*rand("uniform")));

So that x will now contain the text string

(1 + floor((1+50-1)*rand("uniform")))
%LET Seed = %EVAL(&x+&j);

will then resolve to

%LET Seed = %EVAL((1 + floor((1+50-1)*rand("uniform")))+1);

(for &j=1) where the macro processor can't resolve floor and rand (as they are not macro functions), and will throw an error because of non-numeric data.

If you want to create a value, I suggest to use a data _null_ step:

%macro RandBetween(min, max);
(&min + floor((1+&max-&min)*rand("uniform")))
%mend;

%macro DoLoop;
%DO j = 1 %TO 2 ;
data _null_;
x = %RandBetween(1,50);
call symput('Seed',put(x+&j,best.));
run;

proc ... data=... ;

...

seed &seed;

run;

%END;
%MEND DoLoop;
%DoLoop;

You also have to question if macro randbetween is necessary at all.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Occasional Contributor
Posts: 9

Re: Assigning a macro a macro value

Posted in reply to KurtBremser

Thank you @KurtBremser that's running now. I just have one question to help my understanding of the code - what does the code 'best.' do?

Super User
Posts: 8,590

Re: Assigning a macro a macro value

Posted in reply to aoifeoneill
put(x+&j,best.)

converts the numeric values derived from the summation to a character value, as call symput expects two strings as arguments; otherwise you'd get a NOTE about the type conversion, and I don't like them in my codes (I even have measures to search for such NOTEs in log files and throw errors in batch jobs, as undetected type mismatches can cause logical havoc).

best. is just a default format that will work basically all the time and create a string that SAS will always recognize as a number when the macro variable is resolved.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Occasional Contributor
Posts: 9

Re: Assigning a macro a macro value

Posted in reply to KurtBremser

Thanks @KurtBremser for all your help!

Super User
Posts: 12,148

Re: Assigning a macro a macro value

Posted in reply to aoifeoneill

To resolve data step functions such as Floor or Rand in macros you must use the macro function %sysfunc for each function called. Also the macro language doesn't use the the quoted literal strings such as the parameter to Rand quite the same way since it expects text.

 

This does what you were attempting:

%macro RandBetween(min, max);
%let x =  %eval(&min + %sysfunc ( floor((1+&max-&min)* %sysfunc(rand(uniform)) )) );
%put &x;
%mend;

%RandBetween(1,50);

You can see that complex operations involving multiple functions can get quite ugly quickly. I agree with @KurtBremser that datasteps often are much easier to understand and debug than doing things directly in the macro language for many operations.

 

☑ This topic is solved.

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

Discussion stats
  • 5 replies
  • 140 views
  • 0 likes
  • 3 in conversation