优化代码以计算不正确的Euler积分

时间:2017-11-26 10:01:11

标签: c++ algorithm

如何优化以下代码?

Main.cpp的

#include "UtilitiesP.h"
#include "Simpson.h"

int main(void)
{
    double agm(1/functionsP::agm(1, 2));
    double integral( (2/constantsP::kPi) * Simpson(0, constantsP::kPi*0.5, constantsP::kEps, functionsP::eliptic));
    assert(fabs(agm-integral)<constantsP::kEps);

    double firstVal(constantsP::kPi*0.5);
    integral = Simpson(constantsP::kAlmostZero, 10000, constantsP::kEps, functionsP::Dirichlet);

    std::cout << firstVal << std::endl;
    std::cout << integral << std::endl;

    double secondVal(sqrt(constantsP::kPi)*0.5);
    integral = Simpson(constantsP::kAlmostZero, 12, constantsP::kEps, functionsP::Puasson);

    std::cout << secondVal << std::endl;
    std::cout << integral << std::endl;

    double thirdVal(constantsP::kPi/sin(constantsP::kNumberFromEuler*constantsP::kPi));
    integral = Simpson(constantsP::kAlmostZero, 13, constantsP::kEps, functionsP::Euler);

    std::cout << thirdVal << std::endl;
    std::cout << integral << std::endl;


    return 0;
}

Utilities.h

#include <stdexcept>
#include <iostream>

//#define NDEBUG
#include <cassert>

namespace constantsP
{
    const double kPi(3.1415926535897932);
    const double kEps(1.e-12);
    const double kAlmostZero(1.e-7);
    const double kBigNumber(30);
    const double kNumberFromEuler(0.4);
};

namespace functionsP
{
    double agm(const double&, const double&);
    double eliptic(const double&);
    double Dirichlet(const double&);
    double Puasson(const double&);
    double Euler(const double&);
};

Utilities.cpp

#include "UtilitiesP.h"

double functionsP::agm(const double& a, const double& b)
{
    if(a <= 0 || b <= 0)
    {throw std::invalid_argument("Arithmetic-geometric mean is defined only for 0 < a < b.");}

    double aPrev(a), bPrev(b), aCurrent(a), bCurrent(b);
    do
    {
        aPrev = aCurrent;
        bPrev = bCurrent;
        aCurrent = sqrt(aPrev*bPrev);
        bCurrent = (aPrev+bPrev)*0.5;
    }while((aPrev < aCurrent) && (bCurrent < bPrev) && (aPrev < bPrev));

    double res((aPrev <= aCurrent)?aPrev:bPrev);

    return res;
}

double functionsP::eliptic(const double& x)
{
    return 1/sqrt(pow(1*sin(x), 2) + pow(2*cos(x), 2));
}

double functionsP::Dirichlet(const double& x)
{
    return sin(2*x)/x;
}

double functionsP::Puasson(const double& x)
{
    return exp(-(x*x));
}

double functionsP::Euler(const double& x)
{
    return pow(x, constantsP::kNumberFromEuler-1)/(1+x);
}

Simpson.h

#include <cmath>

double Simpson (const double& a, const double& b, const double& eps, double(*const f)(const double&));

Simpson.cpp

#include "Simpson.h"

double Simpson (const double& a, const double& b, const double& eps, double(*const f)(const double&))
{
    double step((b-a)*0.5);
    double s1(step*(f(a)+f(b))), s2(0), s4(4*step*f(a+step));
    double previousSum(0), currentSum(s1+s4);
    int n(2);
    do 
    {
        previousSum = currentSum;
        n += n;
        step *= 0.5;

        s1 *= 0.5;
        s2 = 0.5*s2+0.25*s4;

        s4 = 0;
        for(int i(1); i < n; i+=2)
        {s4 += f(a+i*step);}
        s4 = 4*step*s4;

        currentSum = s1+s2+s4;
    }
    while(eps<fabs(previousSum-currentSum));

    return currentSum/3;
}

运行代码后,您将看到它适用于前两个积分。但它对最后一个非常糟糕。计算它需要很长时间。我可以改变什么才能让它更快地运作?您对这种风格有何评论?

0 个答案:

没有答案