Please explain this divide by zero logic

Reply
New Contributor
Posts: 4

Please explain this divide by zero logic

Hello all,

I'm very much a SAS newbie (much more experienced in R!).  I just started a job requiring the use of SAS for all analytics and so I'm definitely still getting used to it.  I have a macro that I've created (tweaked from a somewhat different purpose) to calculate ratio variables on the fly.  I was getting divide by zero errors in an earlier version of it, but after reading about using the IFN function to protect against those errors, the macro is now performing error free.  The only problem is that I really don't understand what the IFN function is doing exactly in my macro.  Here's the code:

%macro calculate_ratios(oldvarlist, suffix, divisor);

%let k=1;

%let old = %scan(&oldvarlist, &k);

    %do %while("&old" NE "");

            & old.&suffix = ifn(&divisor, &old. / ifn(&divisor, &divisor, 1), 0 , .);

            %let k = %eval(&k + 1);

          %let old = %scan(&oldvarlist, &k);

     %end;

  drop &oldvarlist;

%mend;


I reference this macro in a later data step, where the divisor is a variable containing monetary totals, and oldvarlist is a macro variable containing variables constituting subcomponents of the monetary total variable.  At first glance, to me the IFN function would seem to say "if the divisor is not missing or zero, then evaluate the second argument and return the result, otherwise evaluate/return the 3rd argument, and if missing return the 4th.  However if I don't have that ifn encapsulating the divisor in the second argument then it returns a divide by zero error in the log file.  Why should I need to use ifn on the divisor in the second argument, if that argument only comes into play when the &divisor in the first argument is nonzero/non-missing?  The answer to this probably involves a perspective change on my part...


Thanks in advance!

Esteemed Advisor
Esteemed Advisor
Posts: 7,245

Re: Please explain this divide by zero logic

You are correct in your assumption.  The ifn has the form:

ifn(<condition>,<value if true>,<value if false>)

Lets assume two conditions:

condition 1 - divisor is 0:

ifn(&divisor, &old. / ifn(&divisor, &divisor, 1), 0 , .);

                                             ^ this is the result as condition is false (0) 

&old is then divided by 1.  Otherwise it would be &old / 0 which is where you get you divide by zero warnings.

condition 2 - divisor is 3:

ifn(&divisor, &old. / ifn(&divisor, &divisor, 1), 0 , .);

                                        ^ this is the result as condition is true (!=0) 

&old is then divided by 3.  Otherwise it would be &old / 0 which is where you get you divide by zero warnings.

I would also point out that there really is no need for that macro code at all, there are better ways of coding - code generation, arrays, normalising data etc.

New Contributor
Posts: 4

Re: Please explain this divide by zero logic

But what use is the first argument then, if SAS evaluates the second argument even if the first argument is 0?

Esteemed Advisor
Esteemed Advisor
Posts: 7,245

Re: Please explain this divide by zero logic

Its probably a compilation order thing.  I would word it as:

if &divisor. > 0 then &old.&suffix=&old. / &divisor;


Much clearer that way (apologies for the font changes here).


New Contributor
Posts: 4

Re: Please explain this divide by zero logic

That makes sense.  Would I have been able to code it that way in the macro?

Grand Advisor
Posts: 17,396

Re: Please explain this divide by zero logic

The second ifn accounts for the case when &divisor = 0.

You also want to consider what the first condition is, &divisor which could be anything. It really should be a condition, ie &divisor=0.

assuming divisor=0 and old=25:

1360  data want;

1361  x=ifn(0, 25 / 0, 0 , .);

NOTE: Division by zero detected during the compilation phase, detected at line 1361 column 13.

1362  run;

NOTE: The data set WORK.WANT has 1 observations and 1 variables.

NOTE: DATA statement used (Total process time):

      real time           0.12 seconds

      cpu time            0.00 seconds

1363  data want;

1364  x=ifn(0, 25 /ifn(0, 0, 1), 0 , .);

1365  run;

NOTE: The data set WORK.WANT has 1 observations and 1 variables.

NOTE: DATA statement used (Total process time):

      real time           0.01 seconds

      cpu time            0.00 seconds

Ask a Question
Discussion stats
  • 5 replies
  • 395 views
  • 1 like
  • 3 in conversation