*
;

              options nosource;  /*
    DIFFER -  CALCULATES THE DERIVATIVE FUNCTION FROM A FUNCTION GIVEN
              IN PARAMETERFORM

    Written:  October 31, 1994
    Developed using SAS 6.08 for Windows
    Run able: SAS 6.09 under AIX Unix
    Author:   Arnold Schick
    Procs:    PROC MEANS, PROC DATASETS and PROC SORT
    Other:    SAS MACRO language
    Macros:   only DIFFER
    Note:     Do not use _TEMP_ or _MINMAX_ as a data set name.
              Help informations are given out by calling of
              %DIFFER; or %DIFFER(help); or %DIFFER(?);
              The first two and last two derivative function-values
              are approximated.

    Macro Call: %DIFFER(DATA,RESULT,X,Y,M);


MACRO VARIABLE      DESCRIPTION
------------------+-------------------------------------------------
 In Request:

 DATA               Name of SAS data set with input data. If this
                    parameter is missing _LAST_ is used, on blank
                    parameter stops the macro.

 RESULT             Name of SAS data set created by this macro.
                    If missing or blank _NEW_ is used. One new
                    variable is created: Y_D. Y_D is the variable
                    with the values of the derivative function.

 X                  Variblename of independent variable in input SAS
                    data set DATA. If missing or blank, X is used.

 Y                  Variablename of dependent variable in input SAS
                    data set DATA. If missing or blank, Y is used.

 M                  Value of slope-factor for correction of a
                    slope in input-funtion. If M is zero, blank
                    or missing, a slope correction is not done.


Example:

data one;
  do x=0 to 8*atan(1) by atan(1)/4;
     y=sin(x);
     output;
   end;
run;
*%macro differ (data,result, x, y, m);
       %differ (one ,two);
       %differ (one ,two   , x, y,-0.001);


Reference:  none

For more information:

 Arnold Schick

 University of Marburg
 Academic Computing Center
 Hans-Meerwein-Str.
 35032 Marburg/Lahn   Germany

 Internet: schick@hrz.uni-marburg.de

 If you  find an error-condition (it is provided 'as it is')
 please let me know about this error-condition. And when you
 have good tips for better formulation with SAS, let it also know.
  */

%macro differ (data,result,x,y,m);
options nosource nostimer nonotes nosymbolgen;

  %if &data =  and &result =  and &x =  and &y =  or
            %upcase(&data) = HELP or &data = ? %then %do;
     %put  This macro computes the first derivation of a parameter-function. It needs;
     %put  N defined points: if necessary, the data are to spline or smooth at first.;
     %put  It should called by: DIFFER( input-data, result, indep-var, dep-var, slope );
     %put  where:;
     %put  input-data : datasetname with data for derivation, if missing, _LAST_ is used;
     %put  result     : datasetname of result, if not, _NEW_ is used. Variable Y_D will be created;
     %put  indep-var  : variablename of independent variable in input-data set, default is X;
     %put  dep-var    : variablename of dependent variable in input-data set, default is Y;
     %put  slope      : value of slope-factor to modify input-data, if not, zero is used.;
     %put  Missings or blanks are allowed on parameters.;
     %goto fin;
  %end;

  %if &data   = . %then %do; %let data = _LAST_ ; %put macro-info: input data set is _LAST_; %end;
  %if &data   =   %then %goto quit_1;
  %if &result =  or &result = . %then %do;
                                 %let result = _NEW_;
                                 %put macro-info: output data set is _NEW_;
                                %end;
  %if &x =  or &x = . %then %do; %let x = x; %put macro-info: independent variable is X; %end;
  %if &y =  or &y = . %then %do; %let y = y; %put macro-info: dependent variable is Y; %end;
  data _NULL_;
    b = symget ('m') / 1;
    if b = . then b = 0;
    call symput('m',b);
  run;

  %local empty;
  data _NULL_ ;
    if 0 then set &data nobs=last;
    call symput('empty',last);
    stop;
  run;

  %if &empty < 2 %then %goto quit_2;

  proc means data=&data noprint;
    var &x;
    output out=_MINMAX_ min=min max=max n=n;
  run;

  data _NULL_;
    set _MINMAX_;
    p = round((max-min)/0.01 + 0.5,1);
    if p > n  then
      put 'macro-halt: Please spline/smooth data at first with minimum of ' p ' points, available are n=' n;
    call symput('p',p);
    call symput('n',n);
  run;

  %if &p > &n %then %goto fin;

  proc sort data=&data out=_TEMP_;
    by &x;
  run;

  data _NULL_;
    set _TEMP_  (where=(&x is not missing or &y is not missing));
    length dy dy_1 dy_2 8 ;
    x_previo = Lag(&x);
    y_previo = Lag(&y) + lag(&x)*&m;
    if _N_ > 1 then do;
                 if m ^= 0
                    then dy = -(y_previo - &y + &x*&m) / (&x - x_previo);
                    else dy = -(y_previo - &y        ) / (&x - x_previo);
                 dy_2 = (lag(dy) + dy)/2;
                 dy_1 = lag(dy) -(dy_2 - lag(dy));
                 if _N_ = 3 then do;
                     call symput('dy_2',dy_2);
                     call symput('dy_1',dy_1);
                     stop;
                   end;
               end;
  run;

  data &result (rename=(x_previo=&x y_previo=&y)
                keep  = x_previo y_previo y_d);
    set _TEMP_ (where=(&x is not missing or &y is not missing)) end=last;
    length y_diff y_d 8 ;
    x_previo = lag(&x);
    y_previo = lag(&y) + x_previo*&m;
    if _N_ = 2 then do; y_d=&dy_1; output; end;
    if _N_ > 2 then do;
       if &m ^= 0 then y_diff = -(y_previo - &y + &x*&m)
                                /(&x - x_previo);
                  else y_diff = -(y_previo - &y)
                                /(&x - x_previo);
       y_d = (lag(y_diff) + y_diff)/2;
       if _N_ = 3 then y_d=&dy_2;
       k=lag(y_d);
       output;
    end;
    if last then do;
       x_previo = &x;  y_previo = &y;
       y_d = y_d - (k - y_d);
       output;
    end;
  run;

  proc datasets nolist;
    delete _MINMAX_  _TEMP_;
  quit;

  %goto fin;
  %quit_1 : %put macro-halt: Please define input-data set;
  %goto fin;
  %quit_2 : %put macro-halt: Input data set &data is empty or has less than 2 points;
  %fin  : ;

options source stimer notes;
%mend differ; options source;

*Example:;
data one;
  do x=-2 to 6.29 by atan(1)/128;
     y=cos(x);
     output;
  end;
run;
%differ(one,two);
proc gplot;
  plot (y y_d) * x /overlay;
run;
%differ;

*
;