Numerical integration in C++

后端 未结 4 414
Happy的楠姐
Happy的楠姐 2020-12-29 16:21

I need to integrate a function (of two variables). I know I can do it by using Fubini theorem to integrate one variable functions, then using numerical methods such

4条回答
  •  清歌不尽
    2020-12-29 16:30

    As far as I know there are no functions of the type you are searching for in the standard library. Here is one implementation of the:

    The extended trapezoidal rule.

    For a fixed function f(x) to be integrated between fixed limits a and b, one can double the number of intervals in the extended trapezoidal rule without losing the benefit of previous work. The coarsest implementation of the trapezoidal rule is to average the function at its endpoints a and b. The first stage of refinement is to add to this average the value of the function at the halfway point. The second stage of refinement is to add the values at the 1/4 and 3/4 points.

    A number of elementary quadrature algorithms involve adding successive stages of refinement. It is convenient to encapsulate this feature in a Quadrature structure:

    struct Quadrature
    {  
       //Abstract base class for elementary quadrature algorithms.
       Int n; // Current level of refinement.
    
       virtual Doub next() = 0;
       //Returns the value of the integral at the nth stage of refinement. 
       //The function next() must be defined in the derived class.
    };
    

    Then the Trapzd structure is derived from this as follows:

    template 
    struct Trapzd: Quadrature
    {
        Doub a, b, s; // Limits of integration and current value of integral.
        T &func;
    
        Trapzd() { };
    
        // func is function or functor to be integrated between limits: a and b 
        Trapzd(T &funcc, const Doub aa, const Doub bb)   
            : func(funcc), a(aa), b(bb)
        {
            n = 0;
        }
    
        // Returns the nth stage of refinement of the extended trapezoidal rule. 
        // On the first call (n = 1), the routine returns the crudest estimate  
        // of integral of f x / dx in [a,b]. Subsequent calls set n=2,3,... and
        // improve the accuracy by adding 2n - 2 additional interior points.
        Doub next()
        {
            Doub x, tnm, sum, del;
            Int it, j;
            n++;
    
            if (n == 1)
            {
                return (s = 0.5 * (b-a) * (func(a) + func(b)));
            } 
            else
            {
                for (it = 1, j = 1; j < n - 1; j++)
                {
                    it <<= 1;
                }
                tnm = it;
                // This is the spacing of the points to be added.          
                del = (b - a) / tnm; 
                x = a + 0.5 * del;
    
                for (sum = 0.0,j = 0; j < it; j++, x += del)
                {
                    sum += func(x);
                }
                // This replaces s by its refined value.  
                s = 0.5 * (s + (b - a) * sum / tnm); 
                return s;
            }
        }
    };
    

    Usage:

    The Trapzd structure could be used in several ways. The simplest and crudest is to integrate a function by the extended trapezoidal rule where you know in advance the number of steps you want. If you want 2^M + 1, you can accomplish this by the fragment:

    Ftor func;      // Functor func here has no parameters.
    Trapzd s(func, a, b);
    for(j = 1 ;j <= m + 1; j++) val = s.next();
    

    with the answer returned as val. Here Ftor is a functor containing the function to be integrated.

    Bonus:

    Much better, of course, is to refine the trapezoidal rule until some specified degree of accuracy has been achieved. A function for this is:

    template
    Doub qtrap(T &func, const Doub a, const Doub b, const Doub eps = 1.0e-10)
    {
        // Returns the integral of the function or functor func from a to b. 
        // The constants EPS can be set to the desired fractional accuracy and    
        // JMAX so that 2 to the power JMAX-1 is the maximum allowed number of   
        // steps. Integration is performed by the trapezoidal rule.
    
        const Int JMAX = 20;
        Doub s, olds = 0.0; // Initial value of olds is arbitrary.
    
        Trapzd t(func, a, b);
    
        for (Int j = 0; j < JMAX; j++) 
        {
            s = t.next();
    
            if (j > 5) // Avoid spurious early convergence.
            {
                if (abs(s - olds) < eps * abs(olds) || (s == 0.0 && olds == 0.0)) 
                {
                    return s;
                }
            }
            olds = s;
        }
        throw("Too many steps in routine qtrap");
    }
    

    Typedefs.

    typedef double Doub;    // 64 - bit floating point
    typedef int Int;        // 32 - bit signed integer
    

提交回复
热议问题