Real GaussLobattoIntegral::calculateAbsTolerance( const boost::function<Real (Real)>& f, Real a, Real b) const { Real relTol = std::max(relAccuracy_, QL_EPSILON); const Real m = (a+b)/2; const Real h = (b-a)/2; const Real y1 = f(a); const Real y3 = f(m-alpha_*h); const Real y5 = f(m-beta_*h); const Real y7 = f(m); const Real y9 = f(m+beta_*h); const Real y11= f(m+alpha_*h); const Real y13= f(b); const Real f1 = f(m-x1_*h); const Real f2 = f(m+x1_*h); const Real f3 = f(m-x2_*h); const Real f4 = f(m+x2_*h); const Real f5 = f(m-x3_*h); const Real f6 = f(m+x3_*h); Real acc=h*(0.0158271919734801831*(y1+y13) +0.0942738402188500455*(f1+f2) +0.1550719873365853963*(y3+y11) +0.1888215739601824544*(f3+f4) +0.1997734052268585268*(y5+y9) +0.2249264653333395270*(f5+f6) +0.2426110719014077338*y7); increaseNumberOfEvaluations(13); if (acc == 0.0 && ( f1 != 0.0 || f2 != 0.0 || f3 != 0.0 || f4 != 0.0 || f5 != 0.0 || f6 != 0.0)) { QL_FAIL("can not calculate absolute accuracy " "from relative accuracy"); } Real r = 1.0; if (useConvergenceEstimate_) { const Real integral2 = (h/6)*(y1+y13+5*(y5+y9)); const Real integral1 = (h/1470)*(77*(y1+y13)+432*(y3+y11)+ 625*(y5+y9)+672*y7); if (std::fabs(integral2-acc) != 0.0) r = std::fabs(integral1-acc)/std::fabs(integral2-acc); if (r == 0.0 || r > 1.0) r = 1.0; } if (relAccuracy_ != Null<Real>()) return std::min(absoluteAccuracy(), acc*relTol)/(r*QL_EPSILON); else { return absoluteAccuracy()/(r*QL_EPSILON); } }
Real GaussLobattoIntegral::integrate( const boost::function<Real (Real)>& f, Real a, Real b) const { setNumberOfEvaluations(0); const Real calcAbsTolerance = calculateAbsTolerance(f, a, b); increaseNumberOfEvaluations(2); return adaptivGaussLobattoStep(f, a, b, f(a), f(b), calcAbsTolerance); }
Real GaussKronrodAdaptive::integrateRecursively( const boost::function<Real (Real)>& f, Real a, Real b, Real tolerance) const { Real halflength = (b - a) / 2; Real center = (a + b) / 2; Real g7; // will be result of G7 integral Real k15; // will be result of K15 integral Real t, fsum; // t (abscissa) and f(t) Real fc = f(center); g7 = fc * g7w[0]; k15 = fc * k15w[0]; // calculate g7 and half of k15 Integer j, j2; for (j = 1, j2 = 2; j < 4; j++, j2 += 2) { t = halflength * k15t[j2]; fsum = f(center - t) + f(center + t); g7 += fsum * g7w[j]; k15 += fsum * k15w[j2]; } // calculate other half of k15 for (j2 = 1; j2 < 8; j2 += 2) { t = halflength * k15t[j2]; fsum = f(center - t) + f(center + t); k15 += fsum * k15w[j2]; } // multiply by (a - b) / 2 g7 = halflength * g7; k15 = halflength * k15; // 15 more function evaluations have been used increaseNumberOfEvaluations(15); // error is <= k15 - g7 // if error is larger than tolerance then split the interval // in two and integrate recursively if (std::fabs(k15 - g7) < tolerance) { return k15; } else { QL_REQUIRE(numberOfEvaluations()+30 <= maxEvaluations(), "maximum number of function evaluations " "exceeded"); return integrateRecursively(f, a, center, tolerance/2) + integrateRecursively(f, center, b, tolerance/2); } }
Real GaussLobattoIntegral::adaptivGaussLobattoStep( const boost::function<Real (Real)>& f, Real a, Real b, Real fa, Real fb, Real acc) const { QL_REQUIRE(numberOfEvaluations() < maxEvaluations(), "max number of iterations reached"); const Real h=(b-a)/2; const Real m=(a+b)/2; const Real mll=m-alpha_*h; const Real ml =m-beta_*h; const Real mr =m+beta_*h; const Real mrr=m+alpha_*h; const Real fmll= f(mll); const Real fml = f(ml); const Real fm = f(m); const Real fmr = f(mr); const Real fmrr= f(mrr); increaseNumberOfEvaluations(5); const Real integral2=(h/6)*(fa+fb+5*(fml+fmr)); const Real integral1=(h/1470)*(77*(fa+fb) +432*(fmll+fmrr)+625*(fml+fmr)+672*fm); // avoid 80 bit logic on x86 cpu volatile Real dist = acc + (integral1-integral2); if(dist==acc || mll<=a || b<=mrr) { QL_REQUIRE(m>a && b>m,"Interval contains no more machine number"); return integral1; } else { return adaptivGaussLobattoStep(f,a,mll,fa,fmll,acc) + adaptivGaussLobattoStep(f,mll,ml,fmll,fml,acc) + adaptivGaussLobattoStep(f,ml,m,fml,fm,acc) + adaptivGaussLobattoStep(f,m,mr,fm,fmr,acc) + adaptivGaussLobattoStep(f,mr,mrr,fmr,fmrr,acc) + adaptivGaussLobattoStep(f,mrr,b,fmrr,fb,acc); } }