DATA Step, Macro, Functions and more

Divide by 0 Error in Macro

Accepted Solution Solved
Reply
Occasional Contributor
Posts: 8
Accepted Solution

Divide by 0 Error in Macro

I have a pretty simple macro code:

%macro do_array(var=, num=);   

     %do var_num = 1 %to #

          %if &var&var_num = 0 %then %do;

               perc_&var&var_num = 0;

          %end;

          %else %do;

               perc_&var&var_num = &var&var_num / total;

          %end;

     %end;

%mend;


Basically for all of the variables I'm just trying to get a percentage of the total. When I run it, I get an warning that I'm dividing by zero, but that's what the first step in the if statement is trying to avoid. Along with the warning, instead of a 0 for the value, I'm getting a missing value.


Any suggestions?


Thanks


Accepted Solutions
Solution
‎07-30-2014 07:59 PM
SAS Super FREQ
Posts: 8,743

Re: Divide by 0 Error in Macro

Hi:

  I agree that the TOTAL variable should be checked to avoid the divide by 0 error message, but depending on how you are using your variables, I believe that this %IF statement possibly needs to change to a regular DATA step IF. For example, if VAR=X and Num=1, then your %IF test would seem to be asking this of the macro processor, as if the macro processor has visibility of the DATA step variable X1 (which it doesn't):   
  

%if xi = 0 %then %do;

     perc_x1= 0;

%end;

   

which may not be what you think is going to happen. The %IF statement gets evaluated when the SAS Macro program is executed, but the SAS Macro facility is only generating code that will be executed. So, by the time the code goes to be executed against your data, there are no macro statements left in the code. So generally, Macro %IF statements are NOT used to test data step variables. The value of your data step variables will change with every observation. At the point in time when the macro code is executing, and generating code, no data has actually been read yet. So if you want to test whether X1 is 0, then you need a "regular" DATA step IF.

For example, if you have simple data like this:

grp x1  x2  x3  x4  x5

AAA 5   10  15   .  25

BBB 3    .  11  13  17

CCC 4    5   .   9  11

and you want to calculate new variables pctx1, pctx2, pctx3, pctx4 and pctx5, you can do it without any macro processing. See the attached screen shot.

   

Of course, your program could be more complicated, but I wonder why you are mixing macro programming statements with DATA step variables.

     

cynthia


percent_in_array_no_macro.png

View solution in original post


All Replies
Super User
Posts: 3,111

Re: Divide by 0 Error in Macro

It's the TOTAL variable you need to check for divide by 0.

Occasional Contributor
Posts: 8

Re: Divide by 0 Error in Macro

Sorry about that, I originally had total, but I changed it to the variable to see if it would make a difference. Forgot to change it back before copying it here. Anyway, thank you all so much for your responses.

Solution
‎07-30-2014 07:59 PM
SAS Super FREQ
Posts: 8,743

Re: Divide by 0 Error in Macro

Hi:

  I agree that the TOTAL variable should be checked to avoid the divide by 0 error message, but depending on how you are using your variables, I believe that this %IF statement possibly needs to change to a regular DATA step IF. For example, if VAR=X and Num=1, then your %IF test would seem to be asking this of the macro processor, as if the macro processor has visibility of the DATA step variable X1 (which it doesn't):   
  

%if xi = 0 %then %do;

     perc_x1= 0;

%end;

   

which may not be what you think is going to happen. The %IF statement gets evaluated when the SAS Macro program is executed, but the SAS Macro facility is only generating code that will be executed. So, by the time the code goes to be executed against your data, there are no macro statements left in the code. So generally, Macro %IF statements are NOT used to test data step variables. The value of your data step variables will change with every observation. At the point in time when the macro code is executing, and generating code, no data has actually been read yet. So if you want to test whether X1 is 0, then you need a "regular" DATA step IF.

For example, if you have simple data like this:

grp x1  x2  x3  x4  x5

AAA 5   10  15   .  25

BBB 3    .  11  13  17

CCC 4    5   .   9  11

and you want to calculate new variables pctx1, pctx2, pctx3, pctx4 and pctx5, you can do it without any macro processing. See the attached screen shot.

   

Of course, your program could be more complicated, but I wonder why you are mixing macro programming statements with DATA step variables.

     

cynthia


percent_in_array_no_macro.png
Super User
Posts: 6,946

Re: Divide by 0 Error in Macro

You're misunderstanding what the macro processor does, and when it does it.

If we feed var=xy and num=3 to your macro, it will do the following:

&var&var_num will evaluate to

xy1

xy2

xy3

respectively

All these are clearly not 0, so therefore the macro processor will supply the lines

perc_xy1 = xy1 / total;

perc_xy2 = xy2 / total;

perc_xy3 = xy3 / total;

to the SAS interpreter. Anytime total equates to zero, you get a warning.

The macro processor is invoked BEFORE any data step runs, and does its work without any knowledge about what happens during data step execution. It is only there to generate program text. Repeat the last sentence three times.

You most probably want this in your %do loop:

if total ne 0

then perc_&var&var_num = &var&var_num / total;

else perc_&var&var_num = 0;

This piece of code is then repeatedly supplied vor every var_num to the data step code.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Super User
Super User
Posts: 7,407

Re: Divide by 0 Error in Macro

Just to add, I think what you are trying to achieve is to code your own array processing.  You can do this, per example 2 below, however the use of arrays would be a better idea - example 1:

Example 1:

data have;

  array tot{4} 8.;

  array perc{4} 8.;

  tot{1}=6;

  tot{2}=10;  

  tot{3}=8;

  tot{4}=7;

  do i=1 to 4;

    if tot{i}=0 then perc{i}=0;

    else perc{i}=tot{i} / 45;

  end;

run;

Example 2:

data have;
  array tot{4} 8.;
  array perc{4} 8.;
  tot{1}=6;
  tot{2}=10;  
  tot{3}=8;
  tot{4}=7;
run;

%macro Do_Array (Var=, Num=);
  %do var_num=1 %to &Num.;
    %if &var.&var_num.=0 %then %do;
      perc&var_num.=0;
    %end;
    %else %do;
      perc&var_num.=&var.&var_num. / 45;
    %end;
  %end;
%mend Do_Array;

data want;
  set have;
  %do_Array (Var=tot,Num=4);
run;

Respected Advisor
Posts: 3,777

Re: Divide by 0 Error in Macro

The DIVIDE function returns missing I when you divide by 0.  No message.

23         data _null_;

24            x = divide(1,0);

25            put x=;

26            run;

x=I


27        

28         %put NOTE: %sysfunc(divide(1,0));

NOTE: I

☑ This topic is SOLVED.

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

Discussion stats
  • 6 replies
  • 1389 views
  • 7 likes
  • 6 in conversation