Code covered by the BSD License  

Highlights from
Numerical derivative of analytic function

Numerical derivative of analytic function

by

 

02 Aug 2006 (Updated )

Calculate the numerical derivative of an analytic function with different methods.

dfdx=deriv(f,x,h,method)
% This function returns the numerical derivative of an analytic function.
% Of special note, is the incorporation of the "complex step-derivative"
% approach which offers greatly improved derivative accuracy compared to 
% forward and central difference approximations.  This is especially germain 
% when accuracy at the level of machine precision is a concern.
%
% This function was motivated by: <a href="matlab:web('http://www.biomedicalcomputationreview.org/2/3/8.pdf','-browser')">Complex Step Derivatives</a> authored by Michael Sherman
%   -The function with no inputs generates the example used in the above link.
%   -For more information see the following citation which is also found in the above link:
%      --Martins JR, Sturdza P, and Alonso JJ
%        <a href="matlab:web('http://portal.acm.org/citation.cfm?id=838250.838251','-browser')">The complex-step derivative approximation</a>
%        ACM Trans. Math. Softw. 29(3) (2003)
%
% SYNTAX:   dfdx=deriv(f,x,h,method)
%
% INPUTS:   f      - A function a handle (eg f=@(x) sin(x))
%           x      - Interval over which f(x) is defined
%           h      - Derivative step-size
%           method - Numerical methods used to compute derivative
%                    'forward2' - Two point forward difference
%                    'forward3' - Three point forward difference
%                    'central2' - Two point central difference
%                    'central4' - Four point central difference
%                    'complex'  - Complex step-derivative approximation
%
% OUTPUTS:  dfdx   - Numerical estimate of the derivative of f(x)
%
% Example:  These simple examples produce results in the stack if the "links" are clicked.
%           Compare the accuracy of different methods:
%             <a href="matlab:eval('deriv;')">>> deriv</a>
%
%           Example of how to use the function:
%             <a href="matlab:eval('x=linspace(0,2*pi,1e3);')">>>x=linspace(0,2*pi,1e3);</a>
%             <a href="matlab:eval('f=@(x) sin(x);')">>>f=@(x) sin(x);</a>
%             <a href="matlab:eval('dfdx=deriv(f,x,1e-3,''forward2''); fprintf(''The results are in the STACK.\n'')')">>>dfdx=deriv(f,x,1e-3,'forward2');</a>
%
% DBE 2006.07.31

function dfdx=deriv(f,x,h,method)

DISP=0;  % Flag to turn on/off a plot of the result...this is of marginal utility, therefore the default is ZERO

if nargin==0 % Generate an example of different derivatives and their precision.

  DISP=0;

  f=@(x) sin(3*x).*log(x);

  h2=1e-7;
  h3=1e-5;
  hc=1e-20;
  x=[0.7];

  format long
  dfdxForward2 =(f(x+h2)-f(x))   /   h2 ;                           % Two Point Forward Difference
  dfdxCentral2 =(f(x+h3)-f(x-h3))/(2*h3);                           % Two Point Central Difference

  dfdxForward3 =(-f(x+2*h2)+4*f(x+h2)-3*f(x))/(2*h2);               % Three Point Forward Difference
  dfdxCentral4 =(-f(x+2*h3)+8*f(x+h3)-8*f(x-h3)+f(x-2*h3))/(12*h3); % Four Point Central Difference

  dfdxComplex =imag(f(x+hc*i)   /   hc);                            % Complex difference
  dfdxAnalytic=sin(3*x)./x+3*cos(3*x).*log(x);                      % Analytic result
  
  fprintf('Evaluating the numerical derivative of the analytic function, f(x)=sin(3x).*log(x) @ x=0.7.\n');
  fprintf('Comparison of precision of each numerical method to the analytic result:\n');
  fprintf(' Note the differences in step size.\n');
  fprintf(['  df/dx Forward_2 = ',num2str(dfdxForward2 ,'%.16f'),', Stepsize=',num2str(h2,'%3.1e'),'\n']);
  fprintf(['  df/dx Centra1_2 = ',num2str(dfdxCentral2 ,'%.16f'),', Stepsize=',num2str(h3,'%3.1e'),'\n']);
  fprintf(['  df/dx Forward_3 = ',num2str(dfdxForward3 ,'%.16f'),', Stepsize=',num2str(h2,'%3.1e'),'\n']);
  fprintf(['  df/dx Central_4 = ',num2str(dfdxCentral4 ,'%.16f'),', Stepsize=',num2str(h3,'%3.1e'),'\n']);
  fprintf(['  df/dx Complex   = ',num2str(dfdxComplex  ,'%.16f'),', Stepsize=',num2str(hc,'%3.1e'),'\n']);
  fprintf(['  df/dx Analytic  = ',num2str(dfdxAnalytic ,'%.16f'),'\n']);

  if DISP  % This is *marginally* useful...
    warning('It is VERY hard to see the results visually due to the level of precision involved...');
    figure; hold on;
    xx=linspace(1e-6,1.4,1e3);
    plot(xx,f(xx),'k');

    xx_max=0;
    xx_min=1.4;
    plot([xx_min xx_max],[f(x)+dfdxForward2*(xx_min-x) f(x)+dfdxForward2*(xx_max-x)],'r');
    plot([xx_min xx_max],[f(x)+dfdxCentral2*(xx_min-x) f(x)+dfdxCentral2*(xx_max-x)],'g');
    plot([xx_min xx_max],[f(x)+dfdxAnalytic*(xx_min-x) f(x)+dfdxAnalytic*(xx_max-x)],'b');
  end
elseif nargin==4
  DISP=0;

  switch lower(method)
    case 'forward2'                                           % Two point forward difference
      dfdx=(f(x+h)-f(x))/h;
    case 'central2'                                           % Two point central difference
      dfdx=(f(x+h)-f(x-h))/(2*h);
    case 'forward3'                                           % Three point forward difference
      dfdx=(-f(x+2*h)+4*f(x+h)-3*f(x))/(2*h);
    case 'central4'                                           % Four point central difference
      dfdx =(-f(x+2*h)+8*f(x+h)-8*f(x-h)+f(x-2*h))/(12*h);
    case 'complex'                                            % Complex difference
      dfdx=imag(f(x+h*i)/h);                                  % This is the *magic*
    otherwise
      error('Derivative METHOD not known.');
  end
  
  if DISP  % This is *marginally* useful...
    figure; hold on;
      plot(x,f(x),'r');
      plot(x,dfdx,'b');
      legend('f(x)','df(x)/dx');
  end
else
  error('FOUR input arguments are REQUIRED.');
end

return

Contact us