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

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!

1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

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.

View solution in original post

5 REPLIES 5
Kurt_Bremser
Super User

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.

aoifeoneill
Fluorite | Level 6

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

Kurt_Bremser
Super User
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.

aoifeoneill
Fluorite | Level 6

Thanks @Kurt_Bremser for all your help!

ballardw
Super User

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 @Kurt_Bremser that datasteps often are much easier to understand and debug than doing things directly in the macro language for many operations.

 

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
  • 5 replies
  • 846 views
  • 1 like
  • 3 in conversation