/**********************************************************************/ /* Example 1 */ data _null_; x=0; do i=1 to 10; x+0.1; put x=hex16. '(hex)' x='(formatted dec)'; end; if x=1 then put 'x is equal to 1'; else put 'what happened?'; run; /**********************************************************************/ /* Example 2 */ data _null_; base=16; /* 16 for IBM, 2 for VAX and IEEE */ max_digt=14; /* 14 for IBM, 56 for VAX, 53 for IEEE */ /* Compute maximum integer and display */ max_int=base ** max_digt; put @2 max_int= hex16. '(hex)' max_int comma22. '(dec)'; /* This DO loop attempts to store the five */ /* integers before and after the maximum. Notice */ /* that some of the integers after the maximum */ /* cannot be stored exactly. */ put / @2 'I' @8 'MAX_INT+I (in hex)' @31 'MAX_INT+I (in dec)' / @1 '---' @8 '---------------' @31 '---------------'; do i=-5 to 5; x=max_int+i; put @1 i 2. @10 x hex16. @30 x comma22.; end; run; /**********************************************************************/ /* Example 3 */ data _null_; /* The first expression does not result in a value */ /* of zero. */ x= -16-0.1+16+0.1; put x= hex16. x= '<= expression 1'/; /* By breaking apart the expression, you can see */ /* where representation error is introduced and */ /* where loss of significance occurs. */ x= -16; put x= hex16. x=; x= x-0.1; put x= hex16. x= '<= representation error'; x= x+16; put x= hex16. x= '<= loss of significance'; x= x+0.1; put x= hex16. x= /; /* If you change the order of the operands, the */ /* expression will evaluate correctly. */ x= 16-16+0.1-0.1; put x= hex16. x= '<= expression 2'; run; /**********************************************************************/ /* Example 4 */ data _null_; /* IBM systems */ x=255.115; x_rnd=round(x,.01); y=256.115; y_rnd=round(y,.01); put @10 'IBM systems' / _all_ / ; /* VAX systems */ x=4095.175; x_rnd=round(x,.01); y=4096.175; y_rnd=round(y,.01); put @10 'VAX systems' / _all_ / ; /* IEEE systems */ x=255.155; x_rnd=round(x,.01); y=256.155; y_rnd=round(y,.01); put @10 'IEEE systems' / _all_ / ; run; /**********************************************************************/ /* Example 5 */ %macro eqfuzz(var1, var2, fuzz=1e-12); abs((&var1 - &var2) / &var1) < &fuzz %mend; data _null_; x=0; y=1; do i=1 to 10; x+0.1; end; if x=y then put 'x exactly equal to y'; else if %eqfuzz(x,y) then put 'x close to y'; else put 'x nowhere close to y'; run; /**********************************************************************/ /* Example 6 */ %macro round(var,unit,base=16,fz_digit=12); /* Macro parameters are as follows: */ /* var: variable to be rounded */ /* unit: round-off unit */ /* base: base used for numeric representation */ /* on the platform being used */ /* (base 16 for IBM, base 2 for VAX */ /* and IEEE) */ /* fz_digit: digit in representation where */ /* fuzz occurs */ /* (for IBM: maximum value is 14 */ /* suggested value is 12 */ /* for VAX: maximum value is 56 */ /* suggested value is 50 */ /* for IEEE: maximum value is 53 */ /* suggested value is 48). */ /* Note: Suggested value is less than */ /* maximum to allow for some loss of */ /* significance error as well as */ /* representation error. */ /* */ /* Fuzz factor is computed as follows: */ /* The log in the base of the representation */ /* is determined by taking the natural log of */ /* the value and dividing it by the natural */ /* log of the base. The resulting value is */ /* raised to the next integer to determine the */ /* magnitude of the value. The fz_digit */ /* parameter is subtracted from the magnitude */ /* of the value to determine the magnitude of */ /* the fuzz factor. The base is then raised to */ /* this magnitude and multiplied by the sign */ /* of the value to create the actual fuzz */ /* factor. This fuzz factor is added to the */ /* variable value, and the ROUND function */ /* is called. */ round((&var+ (sign(&var)* &base**(ceil(log(abs(&var))/log(&base))-&fz_digit))), &unit) %mend round; /**********************************************************************/ /* Example 7 */ data _null_; /* IBM systems */ x=255.115; x_rnd=%round(x,.01); y=256.115; y_rnd=%round(y,.01); put @10 'IBM systems' / _all_ / ; /* VAX systems */ x=4095.175; x_rnd=%round(x,.01); y=4096.175; y_rnd=%round(y,.01); put @10 'VAX systems' / _all_ / ; /* IEEE systems */ x=255.155; x_rnd=%round(x,.01); y=256.155; y_rnd=%round(y,.01); put @10 'IEEE systems' / _all_ / ; run; /**********************************************************************/ /* Example 8 */ %macro eqfuzz(var1,var2,fuzz=1e-3); abs(&var1-&var2)<=&fuzz %mend; data a; input byval a_val $ a_group $; cards; 1.0001 A1.0001 A-1-1 1.9999 A1.9999 A-2-1 4.0000 A4.0000 A-4-1 4.9999 A4.9999 A-5-1 5.0000 A5.0000 A-5-2 5.9999 A5.9999 A-6-1 6.0001 A6.0001 A-6-2 7.0000 A7.0000 A-7-1 7.0001 A7.0001 A-7-2 7.0001 A7.0001 A-7-3 ; data b; input byval b_val $ b_group $; cards; 2.0001 B2.0001 B-2-1 3.0000 B3.0000 B-3-1 3.9999 B3.9999 B-4-1 4.0001 B4.0001 B-4-2 4.0001 B4.0001 B-4-3 5.0000 B5.0000 B-5-1 5.0001 B5.0001 B-5-2 6.0000 B6.0000 B-6-1 8.0000 B8.0000 B-8-1 ; run; data c; length a_val b_val a_group b_group $ 8; /* Get next BY value from each data set. */ retain a_count b_count 1; if a_count<=a_nobs then set a(keep=byval rename=(byval=next_a)) point=a_count nobs=a_nobs; if b_count<= b_nobs then set b(keep=byval rename=(byval=next_b)) point=b_count nobs=b_nobs; /* Determine which data set needs to be advanced to */ /* merge current BY group. */ if %eqfuzz(next_a,next_b) then do; read_a=1; read_b=1; end; else if next_a < next_b then do; read_a=1; read_b=0; end; else do; read_a = 0; read_b = 1; end; /* If the end of one of the data sets has been */ /* reached, then get the remaining observations */ /* from the other data set. */ if a_count>a_nobs then do; read_a=0; read_b=1; end; if b_count > b_nobs then do; read_a=1; read_b=0; end; /* Check for beginning of a new BY group. */ if (read_a and not (%eqfuzz(next_a,byval))) or (read_b and not (%eqfuzz(next_b,byval))) then do; /* Reset variables to missing. */ a_val=' '; b_val=' '; a_group=' '; b_group=' '; end; /* Advance data set and write merged observation. */ if read_a then do; set a; a_count+1; end; if read_b then do; set b; b_count+1; end; drop next_a next_b read_a read_b; run; data a2; set a; byval=round(byval); data b2; set b; byval=round(byval); data c2; merge a2 b2; by byval; run; proc sql; create table d as select a.byval, a_val, b_val, a_group, b_group from a full join b on %eqfuzz(a.byval,b.byval); create table d2 as select a2.byval, a_val, b_val, a_group, b_group from a2 full join b2 on a2.byval=b2.byval; /**********************************************************************/