7 #include "GeoGenericFunctions/FunctionNumDeriv.h" 12 FUNCTION_OBJECT_IMP(FunctionNumDeriv)
14 FunctionNumDeriv::FunctionNumDeriv(const AbsFunction *arg1,
unsigned int index):
20 FunctionNumDeriv::FunctionNumDeriv(
const FunctionNumDeriv & right):
22 _arg1(right._arg1->clone()),
23 _wrtIndex(right._wrtIndex)
28 FunctionNumDeriv::~FunctionNumDeriv()
33 unsigned int FunctionNumDeriv::dimensionality()
const {
34 return _arg1->dimensionality();
37 #define ROBUST_DERIVATIVES 38 #ifdef ROBUST_DERIVATIVES 40 double FunctionNumDeriv::f_x (
double x)
const {
45 double FunctionNumDeriv::f_Arg (
double x)
const {
46 _xArg [_wrtIndex] = x;
47 return (*_arg1)(_xArg);
51 double FunctionNumDeriv::operator ()(
double x)
const 53 if (_wrtIndex!=0)
throw std::runtime_error(
"FunctionNumDeriv: dimension mismatch");
54 return numericalDerivative ( &FunctionNumDeriv::f_x, x );
57 double FunctionNumDeriv::operator ()(
const Argument & x)
const 59 if (_wrtIndex >= x.dimension())
throw std::runtime_error(
"FunctionNumDeriv: dimension mismatch");
61 double xx = x[_wrtIndex];
62 return numericalDerivative ( &FunctionNumDeriv::f_Arg, xx );
66 double FunctionNumDeriv::numericalDerivative
67 (
double (FunctionNumDeriv::*f)(
double)
const,
double x )
const {
69 const double h0 = 5 * std::pow(2.0, -17);
71 const double maxErrorA = .0012;
72 const double maxErrorB = .0000026;
74 const double maxErrorC = .0003;
78 const int nItersMax = 6;
80 double bestError = 1.0E30;
83 const double valFactor = std::pow(2.0, -16);
85 const double w = 5.0/8;
86 const double wi2 = 64.0/25.0;
87 const double wi4 = wi2*wi2;
89 double size = fabs((this->*f)(x));
90 if (size==0) size = std::pow(2.0, -53);
92 const double adjustmentFactor[nItersMax] = {
100 for ( nIters = 0; nIters < nItersMax; ++nIters ) {
102 double h = h0 * adjustmentFactor[nIters];
106 double A1 = ((this->*f)(x+h) - (this->*f)(x-h))/(2.0*h);
108 if (fabs(A1) > size) size = fabs(A1);
111 double A2 = ((this->*f)(x+hh) - (this->*f)(x-hh))/(2.0*hh);
113 if (fabs(A2) > size) size = fabs(A2);
116 double A3 = ((this->*f)(x+hh) - (this->*f)(x-hh))/(2.0*hh);
118 if (fabs(A3) > size) size = fabs(A3);
120 if ( (fabs(A1-A2)/size > maxErrorA) || (fabs(A1-A3)/size > maxErrorA) ) {
126 double B1 = ( A2 * wi2 - A1 ) / ( wi2 - 1 );
127 double B2 = ( A3 * wi2 - A2 ) / ( wi2 - 1 );
128 if ( fabs(B1-B2)/size > maxErrorB ) {
134 double ans = ( B2 * wi4 - B1 ) / ( wi4 - 1 );
135 double err = fabs ( ans - B1 );
136 if ( err < bestError ) {
144 double val = ((this->*f)(x+hh) - (this->*f)(x-hh))/(2.0*hh);
145 if ( fabs(val-ans)/size > maxErrorC ) {
156 #endif // ROBUST_DERIVATIVES 160 #ifdef SIMPLER_DERIVATIVES 161 double FunctionNumDeriv::operator ()(
double x)
const 163 if (_wrtIndex !=0)
throw std::runtime_error(
"FunctionNumDeriv: dimension mismatch");
164 const double h=1.0E-6;
165 return ((*_arg1)(x+h) - (*_arg1)(x-h))/(2.0*h);
168 double FunctionNumDeriv::operator ()(
const Argument & x)
const 170 if (_wrtIndex >= x.dimension())
throw std::runtime_error(
"FunctionNumDeriv: dimension mismatch");
171 const double h=1.0E-6;
175 return ((*_arg1)(x1) - (*_arg1)(x0))/(2.0*h);
177 #endif // SIMPLER_DERIVATIVES