Пример #1
0
    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);
        }
    }
Пример #2
0
    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);
    }
Пример #3
0
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);
    }
}
Пример #4
0
 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);
     }
 }