StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
TNumDeriv.cxx
1 // @(#)root/base:$Name: $:$Id: TNumDeriv.cxx,v 1.2 2007/10/24 22:44:46 perev Exp $
2 // Author: Victor Perev 05/08/03
3 
4 
5 #include "TNumDeriv.h"
6 
7 #ifndef __CINT__
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <assert.h>
11 
12 Double_t TNumDeriv::fgTiny=0;
13 Double_t TNumDeriv::fgEpsilon=0;
14 
15 
16 
17 ClassImp(TNumDeriv)
18 ClassImp(TNumDeriv1Test)
19 //______________________________________________________________________________
20 Double_t TNumDeriv::DFcn(Double_t add )
21 {
22  double dfdx,delta=fStep,rerr=0;
23  dfdx = numericalDerivative( add ,delta,rerr);
24  fStep=delta;
25  return dfdx;
26 }
27 
28 
29 //______________________________________________________________________________
30 Double_t TNumDeriv::Tiny()
31 {
32  if (fgTiny) return fgTiny;
33  for (double d = 1; d ; d/=2) { fgTiny=d;}
34  return fgTiny;
35 }
36 
37 //______________________________________________________________________________
38 Double_t TNumDeriv::Epsilon()
39 {
40  if (fgEpsilon) return fgEpsilon;
41  for (double d = 1; (d+1.)>1. ; d/=2) { fgEpsilon=d;}
42  return fgEpsilon;
43 }
44 //______________________________________________________________________________
45 double TNumDeriv::numericalDerivative( double x, double &delta, double &error )
46 {
47 // This code was taken from CLHEP and was slightly improved for the bad cases
48 
49  double h0 = delta;
50  if(!h0) h0 = 5 * pow(2.0, -17);
51 
52  const double maxErrorA = .0012; // These are the largest errors in steps
53  const double maxErrorB = .0000026; // A, B consistent with 8-digit accuracy.
54 
55  const double maxErrorC = .0003; // Largest acceptable validation discrepancy.
56 
57  // This value of gives 8-digit accuracy for 1250 > curvature scale < 1/1250.
58 
59 static const int nItersMax = 6;
60  int nIters;
61  double bestError = 1.0E30;
62  double bestAns = 0;
63  double bestDelta = 0;
64 
65 static const double valFactor = pow(2.0, -16);
66 static const double zero = 1e-10;
67 
68 static const double w = 5.0/8;
69 static const double wi2 = 64.0/25.0;
70 static const double wi4 = wi2*wi2;
71 
72  double F0,Fl,Fr;
73  F0 = Fcn(x);
74  if (!finite(F0)) return 0;
75  double size0 = fabs(F0);
76  if (size0==0) size0 = pow(2.0, -53);
77 
78 static const double adjustmentFactor[nItersMax] = {
79  1.0,
80  pow(2.0, -17),
81  pow(2.0, +17),
82  pow(2.0, -34),
83  pow(2.0, +34),
84  pow(2.0, -51) };
85 
86  for ( nIters = 0; nIters < nItersMax; ++nIters ) {
87  fOutLim=0;
88  double size = size0;
89 
90  double h = h0 * adjustmentFactor[nIters];
91 
92  // Step A: Three estimates based on h and two smaller values:
93 
94  Fr = Fcn(x+h);
95  if (!finite(Fr) || fOutLim) continue;
96  Fl = Fcn(x-h);
97  if (!finite(Fl) || fOutLim) continue;
98 
99  double A1 = (Fr - Fl)/(2.0*h);
100  if (!finite(A1) || fabs(A1) < zero) continue;
101 // size = max(fabs(A1), size);
102  if (fabs(A1) > size) size = fabs(A1);
103 
104  double hh = w*h;
105  Fr = Fcn(x+hh);
106  if (!finite(Fr) || fOutLim) continue;
107  Fl = Fcn(x-hh);
108  if (!finite(Fl) || fOutLim) continue;
109  double A2 = (Fr-Fl)/(2.0*hh);
110  if (!finite(A2) || fabs(A2) < zero) continue;
111 // size = max(fabs(A2), size);
112  if (fabs(A2) > size) size = fabs(A2);
113 
114  hh *= w;
115  Fr = Fcn(x+hh);
116  if (!finite(Fr) || fOutLim) continue;
117  Fl = Fcn(x-hh);
118  if (!finite(Fl) || fOutLim) continue;
119  double A3 = (Fr-Fl)/(2.0*hh);
120 // size = max(fabs(A3), size);
121  if (!finite(A3)|| fabs(A3) < zero) continue;
122  if (fabs(A3) > size) size = fabs(A3);
123 
124  if ( (fabs(A1-A2)/size > maxErrorA) || (fabs(A1-A3)/size > maxErrorA) ) {
125  continue;
126  }
127 
128  // Step B: Two second-order estimates based on h h*w, from A estimates
129 
130  double B1 = ( A2 * wi2 - A1 ) / ( wi2 - 1 );
131  if (!finite(B1)) continue;
132  double B2 = ( A3 * wi2 - A2 ) / ( wi2 - 1 );
133  if (!finite(B2)) continue;
134  if ( fabs(B1-B2)/size > maxErrorB ) {
135  continue;
136  }
137 
138  // Step C: Third-order estimate, from B estimates:
139 
140  double ans = ( B2 * wi4 - B1 ) / ( wi4 - 1 );
141  if (!finite(ans)) continue;
142  double err = fabs ( ans - B1 );
143  if ( err < bestError ) {
144  bestError = err;
145  bestAns = ans;
146  bestDelta = h;
147  }
148 
149  // Validation estimate based on much smaller h value:
150 
151  hh = h * valFactor;
152  double val = (Fcn(x+hh) - Fcn(x-hh))/(2.0*hh);
153  if (!finite(val) || fOutLim) continue;
154  if ( fabs(val-ans)/size > maxErrorC ) {
155  continue;
156  }
157 
158  // Having passed both apparent accuracy and validation, we are finished:
159  break;
160  }
161  delta = bestDelta;
162  error = bestError;
163  return bestAns;
164 
165 }
166 
167 #endif