%global stind endind;
%let stind=0; %let endind=500;
%macro m_sinx(nx, baseratio, noiseratio);
/*%let nx=30;*/
data temp_simu_sin_od;
%do i=1 %to &nx;
ybase=(round(ranuni(&i.),0.1)+0.1)*&baseratio.;
%do x=&stind. %to &endind.;
tick=&i.;
ynoise=(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
y=ybase*sin(&x./200)+(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
ind=&x.;
output;
%end;
%end;
run;quit;
%mend;
%m_sinx(300,20,0.5);
When nx=30, it takes only seconds. But when nx=300, it takes forever. I have to stop in middle.
Any wrong with the coding?!
21830
21831 %m_sinx(30,20,0.5);
NOTE: The data set WORK.TEMP_SIMU_SIN_OD has 15030 observations and 5 variables.
NOTE: DATA statement used (Total process time):
real time 3.52 seconds
cpu time 3.56 seconds
21832
21833 %m_sinx(300,20,0.5);
NOTE: DATA statement used (Total process time):
real time 4:48.31
cpu time 4:03.35
Start by removing the quit statement.
Would replace the macro loops with normal loops:
%macro m_sinx(nx, baseratio, noiseratio);
data temp_simu_sin_od;
do i = 1 to &nx.;
ybase = (round(ranuni(i) ,0.1) + 0.1) * &baseratio.;
do x = &stind. to &endind.;
tick = i;
ynoise = (ranuni(i) - 0.5) * &noiseratio. * 2 * ranuni(x);
y = ybase * sin(x / 200) + (ranuni(i) - 0.5) * &noiseratio. * 2 * ranuni(x);
ind = x;
output;
end;
end;
drop i x;
run;
%mend;
Log:
50 %m_sinx(300, 20, 0.5);
NOTE: The data set WORK.TEMP_SIMU_SIN_OD has 150300 observations and 5 variables.
NOTE: Verwendet wurde: DATA statement - (Gesamtverarbeitungszeit):
real time 0.03 seconds
cpu time 0.03 seconds
Start by removing the quit statement.
Would replace the macro loops with normal loops:
%macro m_sinx(nx, baseratio, noiseratio);
data temp_simu_sin_od;
do i = 1 to &nx.;
ybase = (round(ranuni(i) ,0.1) + 0.1) * &baseratio.;
do x = &stind. to &endind.;
tick = i;
ynoise = (ranuni(i) - 0.5) * &noiseratio. * 2 * ranuni(x);
y = ybase * sin(x / 200) + (ranuni(i) - 0.5) * &noiseratio. * 2 * ranuni(x);
ind = x;
output;
end;
end;
drop i x;
run;
%mend;
Log:
50 %m_sinx(300, 20, 0.5);
NOTE: The data set WORK.TEMP_SIMU_SIN_OD has 150300 observations and 5 variables.
NOTE: Verwendet wurde: DATA statement - (Gesamtverarbeitungszeit):
real time 0.03 seconds
cpu time 0.03 seconds
Hello @hellohere,
The main issue with your code -- that it creates thousands of lines of code, while it should just create data -- is resolved by @andreas_lds's suggestion.
Also note that changing the seed of the RANUNI function within a DATA step is pointless: You get exactly the same result if you replace all those seed values by the first, which is 1 in your case. There are good reasons to switch from the deprecated RANUNI function to the RAND function (here: with the 'UNIFORM' distribution) anyway: see Six reasons you should stop using the RANUNI function to generate random numbers. (Then you would set the seed with the CALL STREAMINIT routine.)
To streamline the code further, you could replace variable x by variable ind and variable i by tick. Then you could delete the two assignment statements (for tick and ind) and the DROP statement.
Is this due to usage of %do instead of do inside macro?!
@hellohere wrote:
Is this due to usage of %do instead of do inside macro?!
Yes, the macro %DO loops unnecessarily generated tons of DATA step code, whereas the DO loops together with the OUTPUT statement in the inner loop efficiently create the data, as intended.
@hellohere wrote:
Is this due to usage of %do instead of do inside macro?!
Become your own macro interpreter and see for yourself.
With the %DO loops the macro is generating code like:
data temp_simu_sin_od;
ybase=(round(ranuni(&i.),0.1)+0.1)*&baseratio.;
tick=&i.;
ynoise=(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
y=ybase*sin(&x./200)+(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
ind=&x.;
output;
ynoise=(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
y=ybase*sin(&x./200)+(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
ind=&x.;
output;
ynoise=(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
y=ybase*sin(&x./200)+(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
ind=&x.;
output;
...
ybase=(round(ranuni(&i.),0.1)+0.1)*&baseratio.;
tick=&i.;
ynoise=(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
y=ybase*sin(&x./200)+(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
ind=&x.;
output;
ynoise=(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
y=ybase*sin(&x./200)+(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
ind=&x.;
output;
ynoise=(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
y=ybase*sin(&x./200)+(ranuni(&i.)-0.5)*&noiseratio.*2*ranuni(&x.);
ind=&x.;
output;
...
run;
So the data step will take a very long time to compile before it can even begin to generate the data.
It is always best to know what code you want the macro to emit before you start writing the macro.
It's your turn to help shape SAS Innovate 2027. Share your expertise and inspire the SAS community.
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.
Ready to level-up your skills? Choose your own adventure.