Date: Tue, 18 Jun 1996 21:46:37 -0600
Reply-To: Andrew James Llwellyn Cary <ajlcary@IX.NETCOM.COM>
Sender: "SAS(r) Discussion" <SAS-L@UGA.CC.UGA.EDU>
From: Andrew James Llwellyn Cary <ajlcary@IX.NETCOM.COM>
Organization: Cary Consulting Services
Subject: Re: Is this a bug???
<LOTS OF CODE DELETED>
> The problem here is: Although the percent in data Q1 is exactly 100
> (as it should be), the dataset test1 can not output anycase. The
> dataset test2 has one case with count 11 and percent 100 instead.(Note
> that in test2 I use subsetting statement 'if percent GT 100' ) .
> When I try to print it, however, even with format 20.16, I still get
> all 0's after decimal point.
>
> Another interesting thing is if the count number were not 11, 'if
> percent EQ 100' works well in dataset test1.
>
> Is is a bug in SAS? or someone can give me other explaination?
>
> TIA
>
> Andy
Is it a bug? Not really. Just an artifact.
The problem (once again) is that what you saw isn't what you got.
Computers do not 'think' in decimal numbers. They think in binary
numbers.
Floating point numbers are not exact. They are a binary fraction raised
to a normalized binary power. The format you are using takes this binary
fraction and turns it into a set of characters representing that
fraction to the precision you specify. The w.d format will always look
better then the real data. To see the real value you must use a Hex16.
format (it will return a hex string representation of the true binary
value in memory. This can be enlightening. The value HUNDRED was set to
100 using an assignment statement. The PERCENT is from your program.
HUNDRED=4059000000000000
PERCENT=4059000000000001
as you can see Percent is indeed greater then 100 (the rightmost bit)
The number 11 (or I suspect any prime) used in the percent calculation
is most likely the culprit. There just isn't any graceful way to
represent division by a prime >2 as a binary fraction..
How to avoid this? There are a couple of things you can do.
Use the ROUND function to round PERCENT to some arbitrary precision:
IF ROUND(100,.1) = ROUND(PERCENT,.1);
Code your comparisons with an arbitrary 'fuzz' around the comparison:
IF 0.000000001 <= ABS(PERCENT-100);
use the FUZZ function to clean it up.
IF FUZZ(PERCENT) = 100;
would all work. The FUZZ function was written with this kind of
comparison in mind. It returns an integer if the argument is within
10e-12 of an integer, otherwise it returns the argument.
--
Andrew J. L. Cary | I Reckon that the Opinions
Senior Curmudgeon | expressed here DO represent
Cary Consulting Services, Newark, CA | those of the management of
ajlcary@ix.netcom.com | Cary Consulting Services