BookmarkSubscribeRSS Feed
monsieur
Obsidian | Level 7

Hi everyone, 

 

I've been trying to write a macro using DOSUBL to return a string so I can use it directly in DATA Step. Inside the DOSUBL block, I call another macro using CALL EXECUTE which will return 2 macro variables.

 

Here is the macro which returns 2 macro variables :

%macro Binomial_p(r,n,alpha=0.05);

/* Create data set param6 */
data param6;
	r = &r.;
    n = &n.;
    alpha = &alpha.;
    p = r/n;
	q = 1 - p;
    z = probit(1-alpha/2);
    output;
    max_idx = alpha/2;
	min_idx = 1 - alpha/2;

	do j = 0.000001 to 0.999999 by 0.00001;
		if (r > 0 and r < n) then a2 = 0.5*probbnml(j,n,r-1) + 0.5*probbnml(j,n,r);
		output;
	end;
run;

/* Create data set min & max */
proc sql;
	create table max as
	select max(j) as upper6
	from param6		
	where a2 > max_idx and r > 0 and r < n;

	create table min as
	select min(j) as lower6
	from param6		
	where a2 <= min_idx and r > 0 and r < n;
quit;

/* Store lower6 & upper6 into macro variables for future use */
%global lower6 upper6;
data ci6;
	merge param6(obs=1) min max;
	if r = 0 then do;
		lower6 = 0;
		upper6 = 1 - alpha**(1/n);
	end;
	if r = n then do;
		lower6 = alpha**(1/n);
		upper6 = 1;
	end;
	call symputx("lower6",lower6);
	call symputx("upper6",upper6);
run;

/* Delete unnecessary data sets */
proc datasets nolist; 
	delete param6 min max ci6; 
run;

%mend Binomial_p;

/*
%Binomial_p(r=81,n=263,alpha=0.05);
%put lower6=&lower6. upper6=&upper6.;
*/

 Here is the main DOSUBL block :

%macro CI_Proportion(r,n,method,alpha=0.05);

%local ci;
%let rc = %sysfunc(dosubl(%str(

data _null_;
	/* Define some values */
    r = &r.;
    n = &n.;
    alpha = &alpha.;
    p = r/n;
	q = 1 - p;
    z = probit(1-alpha/2);
	/* 6.  Binomial-based, Mid-p (Binomial_p) */
	if &method. = "Binomial_p" then do;
		call execute('%Binomial_p(r=&r.,n=&n.,alpha=&alpha.);');
		lower = &lower6.;
		upper = &upper6.;
	end;
	/* Store ci into macro variable */
	ci = strip(put(r,10.)) || " " || strip(put(p,10.4)) || "(" || strip(put(lower,10.4)) || "-" || strip(put(upper,10.4)) || ")";
	call symputx("ci",ci);
run;

)));
/* Return macro variable ci */
&ci.

%mend CI_Proportion;

%put %CI_Proportion(r=81,n=263,method="Binomial_p",alpha=0.05);

I ran into 2 errors :

ERROR 386-185: Expecting an arithmetic expression.
ERROR 200-322: The symbol is not recognized and will be ignored.
386: LINE and COLUMN cannot be determined.
WARNING: Apparent symbolic reference LOWER6 not resolved.
WARNING: Apparent symbolic reference UPPER6 not resolved.

For the second error, I think I can't use 2 macro variables after CALL EXECUTE because they don't exist yet. Is it correct ? 

For the first one, I couldn't find where is the error.

 

Thanks in advance for any input !!!

3 REPLIES 3
FriedEgg
SAS Employee
You cannot use call execute with a macro like this. You would have to run it as a dosubl also. You should really rethink your entire design here. Not good.
Tom
Super User Tom
Super User

Watch out for inteaction between local and global symbol tables when using DOSSUBL.

See this thread.

https://communities.sas.com/t5/Base-SAS-Programming/DOSUBL-scope-of-returned-macro-variables/m-p/138...

 

FriedEgg
SAS Employee

To build, somewhat, on your post from yesterday, try using PROC FCMP

 

proc fcmp;

subroutine Binomial_p(r, n, alpha, upper6, lower6);
   outargs upper6, lower6;
   p = r/n;
   q = 1 - p;
   z = probit(1-alpha/2);

   if r = 0 then do;
      lower6 = 0;
	  upper6 = 1 - alpha**(1/n);
   end;
   else if r = n then do;
      lower6 = alpha**(1/n);
	  upper6 = 1;
   end;
   else do;
      length max_idx min_idx rc j a2 8;
      max_idx = alpha/2;
      min_idx = 1 - alpha/2;
      
      declare hash h(ordered:'d');
      declare hiter hi('h');
         rc = h.definekey('j');
         rc = h.definedata('a2');
      rc = h.definedone();

      do j = 0.000001 to 0.999999 by 0.00001;
         if (r > 0 and r < n) then do;
	        a2 = 0.5*probbnml(j,n,r-1) + 0.5*probbnml(j,n,r);
		    if a2 <= a2 > max_idx then rc = h.add();
	     end;
      end;

      rc = hi.first();
      if a2 > max_idx then upper6 = j;
      rc = hi.last();
	  if a2 <= min_idx then lower6 = j;
   end;
endsub;

function CI_Proportion(r, n, method $, alpha) $;
   p = r/n;
   q = 1 - p;
   z = probit(1-alpha/2);

   length upper lower 8;
   if method = "Binomial_p" then call Binomial_p(r,n,alpha,upper,lower);

   ci = strip(put(r,10.)) || " " || strip(put(p,10.4)) || "(" || strip(put(lower,10.4)) || "-" || strip(put(upper,10.4)) || ")";
   return(ci);
endsub;

ci_proportion = CI_Proportion(81,263,"Binomial_p",0.05);
put ci_proportion=;

quit;

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 3 replies
  • 1288 views
  • 0 likes
  • 3 in conversation