## Assigning a macro a macro value

Solved
Occasional Contributor
Posts: 9

# 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: 9,925

## Re: Assigning a macro a macro value

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
How to convert datasets to data steps
How to post code

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

## Re: Assigning a macro a macro value

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
How to convert datasets to data steps
How to post code
Occasional Contributor
Posts: 9

## Re: Assigning a macro a macro value

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: 9,925

## Re: Assigning a macro a macro value

``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
How to convert datasets to data steps
How to post code
Occasional Contributor
Posts: 9

## Re: Assigning a macro a macro value

Thanks @KurtBremser for all your help!

Super User
Posts: 13,358

## Re: Assigning a macro a macro value

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.