*
;

/* This macro selects from dataset IN  n PCT
   data and stores the choosen data into OUT.
   No duplicate observation will be selected.

   IN, OUT  macro call parameter for the dataset names IN and OUT
   PCT      macro call parameter for the numeric value of pct.
   _RESERVE internal dataset name which is created by this macro

Note:     no default macro parameters are in use.
          Selection of a lower number of obersations results inexactly.

Written:  January 16, 1996
Author:   Arnold Schick, University of Marburg/Germany
*/
       options nosource;
%macro choice(in,out,pct);
options nonotes nomprint nosymbolgen nostimer nosource;
  data &out  (drop=stored any_more res_fact)
    _reserve (drop=stored any_more res_fact);
    set &in nobs=N end=last;
    which = _N_;
      if round(log(0.66-1/(0.01*&pct-1))*ranuni(0),1)
          then do;
                 stored+1;
                 output &out;
               end;
          else do;
                 if &pct > 90 then output _reserve;
                              else if &pct < 84 then res_fact = 0.0065;
                                                else res_fact = 0.0020;
                 if round(log(0.66-1/(res_fact*&pct-1))*ranuni(0),1)
                      then output _reserve;
               end;
    any_more = stored - round(&pct/100*N,1);
    if last then call symput('diff',any_more);
  run;
  %if &diff > 0  %then %do;
                         data &out (drop=i);
                           set &out nobs=N;
                           if i < &diff
                               then if round(log(0.66-1/(&diff/N-1))
                                 *ranuni(0),1) then do; i+1; delete; end;
                         run;
                       %end;
                %else %if &diff ^= 0 %then %do;
                        data _reserve (drop=i);
                          set _reserve nobs=N;
                          if i < N+&diff
                               then if round(log(0.66-1/((N+&diff)
                                 /N-1))*ranuni(0),1) then do; i+1;
                                                            delete; end;

                        run;
                        data &out;
                          update &out _reserve;
                          by which;
                        run;
                      %end;

  proc datasets nolist;
     delete _reserve;
  quit;
  options notes;
  data &out;
    set &out;
  run;
options stimer source;

%mend choice; options source;


*Example;

   data one;
   do h=0 to 9999;
     p=h+h;
     output;
   end;
   run;

%choice(one,two,23);    *selects 23% of data from ONE and stores into TWO;

proc print data=two;
run;

%choice(one,two,43.21); *selects 43.2% of data from ONE and stores into TWO;

proc print data=two;
run;

*
;