- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
IMO or in terms of project, value 253.3 or 253.30 or 253.0000000000 should be equal. However the following SAS code says it is not equal. I'm OK if the string is converted to numeric while we do the comparison in the following code but the condition is I have to preserve the format numx18.10.
Right now the following comparison is not equal but I want it to resolve it as equal.
If strip('253.3') ne strip(put(input('253.3',numx18.10),numx18.10))
then num_error=1;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Why are you treating numbers as strings? That is, to be very polite, not a bright thing to do.
If you want 253.3 and 253 to be equal, just do this:
data test;
input x y;
if round(x,1) = round(y,1)
then test = "yes";
else test = "no";
datalines;
253.3 253
;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
253.311 with 253.312 then it should resolve as not equal. I will loose this
behavior if I use round function.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
So you consider a difference of .001 important, but a difference of .3 (larger by a factor of 300!) not?
What is your rule for this?
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
E.g
253.3 and 253.300 should be equal.
253.3 and 253.3000 should be equal
253.312 and 253.313 is not equal
253.3 and 253.31 is not equal
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Quote from your original post:
"IMO or in terms of project, value 253.3 or 253.30 or 253.0000000000 should be equal. "
Please proofread your posts, and edit them if you find such crucial mistakes.
But my basic point stays: Store numbers as NUMBERS, and you can make simple comparisons.
If not, input values to numbers, and compare those:
data test; input x :$20. y :$20.; if input(x,32.) = input(y,32.) then test = "yes"; else test = "no"; datalines; 253.3 253 253.3 253.300000000 253.312 253.313 ; proc print data=test noobs; run;
Result:
x y test 253.3 253 no 253.3 253.300000000 yes 253.312 253.313 no
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi @Babloo,
I suspect the reason why you're doing this is that you encountered numeric representation issues.
Example:
data _null_;
x=253.3;
y=759.9/3;
put (x y)(/=25.20);
if x ne y then put 'different!';
run;
Result (with SAS 9.4M5 under Windows):
x=253.30000000000000000000 y=253.30000000000000000000 different!
So, it happens easily to obtain numbers which should be equal (mathematically) and which look equal (with common display formats), but SAS considers them different because of tiny rounding errors.
Similar issues can even occur without involving calculations, just by appending zeros to decimal fractions (see examples further below).
The standard way of dealing with said issues is using the ROUND function with a suitable rounding unit -- where "suitable" means: small enough not to influence results, but big enough to correct rounding errors in the least significant bits. It depends to some extent on the order of magnitude of the values to be rounded, but a value of 1E-9 is suitable for many practical applications.
Example:
data test;
input x;
r=round(x,1e-9);
cards;
1E-5
1.0E-5
1.00E-5
1.000E-5
253.3
253.3000000000000000000
253.30000000000000000000000
253.300000001
;
proc print data=test;
format x r hex16.;
run;
Result:
Obs x r 1 3EE4F8B588E368F1 3EE4F8B588E368F1 2 3EE4F8B588E368F0 3EE4F8B588E368F1 3 3EE4F8B588E368F0 3EE4F8B588E368F1 4 3EE4F8B588E368F1 3EE4F8B588E368F1 5 406FA9999999999A 406FA9999999999A 6 406FA99999999999 406FA9999999999A 7 406FA9999999999B 406FA9999999999A 8 406FA999999A230A 406FA999999A230A
Note how the ROUND function maps the different internal values of obs. 1 vs. 2 and obs. 3 vs. 4 to the same value. The same goes for obs. 5, 6 and 7 -- but without losing the ability to distinguish between values that differ by 1E-9 (the rounding unit), see obs. 8.
Edit: Your attempt using the NUMX18.10 (in)format must fail in general because a value displayed with this format will mostly have more than one decimal place (in fact up to 10 -- if space permits) and contain a comma rather than a decimal point, so it can't be equal to something like "253.3". Moreover, note that using the decimal specification (e.g. numx18.10) in the informat is risky because it causes a division of integers by a power of 10 and is ignored for values already containing a decimal point (or comma in this case).