Date: Wed, 2 Nov 2005 11:22:13 -0600
Reply-To: PuddingDotManAtGmailDotCom@listserv.cc.uga.edu
Sender: "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From: Pudding Man <pudding.man@GMAIL.COM>
Subject: Re: Trying to avoid division by zero...
In-Reply-To: <103120052235.2396.43669C3E000A282F0000095C220076106405029A06CE9907@comcast.net>
Content-Type: text/plain; charset=ISO-8859-1
On Mon, 31 Oct 2005 22:35:43 +0000, iw1junk@COMCAST.NET (Ian Whitlock) wrote:
>I thought there would be a trivial macro answer
Macro ???
>to Julie's question in
>version 9, but I was shocked to find that
>
> data _null_ ;
> input x y ;
> z = ifn(missing(y) or y=0, . , x/y ) ;
> put _all_ ;
> cards ;
> 1 0
> 5 .
> 6 3
> ;
>
>produces missing value messages. Isn't this half the point of having the
>IFN function? I feel cheated.
V9 function IFN occurred to me also when I read Julie's
post. Ian beat me to the test.
From the V9 doc:
-------------------------------------------------------------------
Syntax
IFN(logical-expression, value-returned-when-true,
value-returned-when-false <,value-returned-when-missing>)
...
The IFN function uses conditional logic that enables you to
select among several different values based on the value of
a logical expression.
IFN evaluates the first argument, then logical-expression.
If logical-expression is true (that is, not zero and not
missing), then IFN returns the value in the second argument.
If logical-expression is a missing value, and you have a
fourth argument, then IFN returns the value in the fourth
argument. If logical-expression is false, IFN returns the
value in the third argument
-------------------------------------------------------------------
One might well assume that, if IFN was optimized for performance,
it would evaluate arg1 and then compute only one of the
following expressions. This doesn't appear to be the case.
To wit (count the 'div. by 0' messages):
54 data _null_;
55 n=1; d=0;
56 junk = ifn(d, n/d , ., .);
57 put _all_;
58 run;
NOTE: Division by zero detected at line 56 column 17.
n=1 d=0 junk=. _ERROR_=1 _N_=1
n=1 d=0 junk=. _ERROR_=1 _N_=1
NOTE: Mathematical operations could not be performed at the following
places. The results of
the operations have been set to missing values.
Each place is given by: (Number of times) at (Line):(Column).
1 at 56:17
...
59
60 data _null_;
61 n=1; d=0;
62 junk = ifn(d, n/d , n/d, .);
63 put _all_;
64 run;
NOTE: Division by zero detected at line 62 column 17.
NOTE: Division by zero detected at line 62 column 23.
n=1 d=0 junk=. _ERROR_=1 _N_=1
n=1 d=0 junk=. _ERROR_=1 _N_=1
NOTE: Mathematical operations could not be performed at the following
places. The results of
the operations have been set to missing values.
Each place is given by: (Number of times) at (Line):(Column).
1 at 62:17 1 at 62:23
...
65
66 data _null_;
67 n=1; d=0;
68 junk = ifn(d, n/d , n/d, n/d);
69 put _all_;
70 run;
NOTE: Division by zero detected at line 68 column 17.
NOTE: Division by zero detected at line 68 column 23.
NOTE: Division by zero detected at line 68 column 28.
n=1 d=0 junk=. _ERROR_=1 _N_=1
n=1 d=0 junk=. _ERROR_=1 _N_=1
NOTE: Mathematical operations could not be performed at the following
places. The results of
the operations have been set to missing values.
Each place is given by: (Number of times) at (Line):(Column).
1 at 68:17 1 at 68:23 1 at 68:28
...
It appears that it computes (and issues messages for) all
expressions coded in the IFN function, then returns the
correct one.
The doc doesn't say how the correct value is returned, so
it isn't a "Real, Live Bug". To a material extent, they
make a fine science of -not- writing doc such that much of
anything can be technically called a "Bug".
Of course, performance can be relatively miserable:
139 %let iter = 1e8;
140
141 data _null_;
142 retain d 0 a b c 14;
143 do i = 1 to &iter;
144 junk = ifn(d, a , b, c);
145 end;
146 run;
NOTE: DATA statement used (Total process time):
real time 11.49 seconds
cpu time 11.25 seconds
147
148 data _null_;
149 retain d 0 a b c 14;
150 do i = 1 to &iter;
151 if d then junk = a;
152 else if d = 0 then junk = b;
153 else if missing(d) then junk = c;
154 end;
155 run;
NOTE: DATA statement used (Total process time):
real time 6.39 seconds
cpu time 6.27 seconds
"Parts" of the DATA step compile. Functions i.e. IFN
interpret? It is practical to engineer an executable
such as IFN to evaluate a logical expression and then
compute only one of a list of subsequent expressions?
What we have here is a "Design Error" (at least in the
context of performance)?
Note that this is -not- a "Version X.0" (i.e. SAS V9.0)
problem. The code above ran in W2kP 9.1.3 SP3. I'm inclined
to think we were all cheated.
Zalut,
Puddin'
*****************************************************************
*** Puddin' Man PuddingDotMan at GmailDotCom **
*****************************************************************;
Pease pudding hot,
Pease pudding cold,
Pease pudding in the pot
Nine days old.