更高效的集成循环

时间:2012-05-24 16:45:57

标签: c# performance integration

public double Integral(double[] x, double intPointOne, double intPointTwo)
{
    double integral = 0;
    double i = intPointOne;
    do
    {
        integral += Function(x[i])*.001;
        i = i + .001;
    }
    while (i <= intPointTwo);
    return integral;
}

这是一个函数,我必须简单地使用部分的总和来集成x1-x2中的函数。如何使这个循环更有效(使用更少的循环),但更准确?

Function改变每次迭代,但它应该是无关紧要的,因为它的数量级(或边界)应保持相对相同...

4 个答案:

答案 0 :(得分:6)

1)查看http://apps.nrbook.com/c/index.html的第4.3节,了解不同的算法。

2)要控制精度/速度因子,您可能需要指定边界x_lowx_high以及积分中需要的切片数量。所以你的功能看起来像这样

// Integrate function f(x) using the trapezoidal rule between x=x_low..x_high
double Integrate(Func<double,double> f, double x_low, double x_high, int N_steps)
{
    double h = (x_high-x_low)/N_steps;
    double res = (f(x_low)+f(x_high))/2;
    for(int i=1; i < N; i++)
    {
        res += f(x_low+i*h);
    }
    return h*res;
}

一旦理解了这种基本集成,就可以继续使用数字Recipies和其他资源中提到的更精细的方案。

要使用此代码,请发出A = Integrate( Math.Sin, 0, Math.PI, 1440 );

之类的命令

答案 1 :(得分:1)

这里通过方法计算积分:左手,梯形和中点

/// <summary>
/// Return the integral from a to b of function f
/// using the left hand rule
/// </summary>
public static double IntegrateLeftHand(double a, 
                                       double b, 
                                       Func<double,double> f, 
                                       int strips = -1) {

    if (a >= b) return -1;  // constraint: a must be greater than b

    // if strips is not provided, calculate it
    if (strips == -1) { strips = GetStrips(a, b, f); }  

    double h = (b - a) / strips;
    double acc = 0.0;

    for (int i = 0; i < strips; i++)    { acc += h * f(a + i * h); }

    return acc;
}

/// <summary>
/// Return the integral from a to b of function f 
/// using the midpoint rule
/// </summary>
public static double IntegrateMidPoint(double a, 
                                       double b, 
                                       Func<double, double> f, 
                                       int strips = -1) {

    if (a >= b) return -1;  // constraint: a must be greater than b

    // if strips is not provided, calculate it
    if (strips == -1) { strips = GetStrips(a, b, f); }  

    double h = (b - a) / strips;
    double x = a + h / 2;
    double acc = 0.0;

    while (x < b)
    {
        acc += h * f(x);
        x += h;
    }

    return acc;
}

/// <summary>
/// Return the integral from a to b of function f
/// using trapezoidal rule
/// </summary>
public static double IntegrateTrapezoidal(double a, 
                                          double b, 
                                          Func<double, double> f, 
                                          int strips = -1) {

    if (a >= b) return -1;   // constraint: a must be greater than b

    // if strips is not provided, calculate it
    if (strips == -1) { strips = GetStrips(a, b, f); }  

    double h = (b - a) / strips;
    double acc = (h / 2) * (f(a) + f(b));

    for (int i = 1; i < strips; i++)    { acc += h * f(a + i * h); }

    return acc;
}


private static int GetStrips(double a, 
                             double b, 
                             Func<double, double> f) {
    int strips = 100;

    for (int i = (int)a; i < b; i++)
    {
        strips = (strips > f(i)) ? strips : (int)f(i);      
    }

    return strips;
}


Console.WriteLine("w/ strips:{0}", IntegrateLeftHand(0, 3.14, Math.Sin, 1440));
Console.WriteLine("without strips:{0}", IntegrateMidPoint(0, 30, x => x * x));

// or with a defined method for f(x)

public static double myFunc(x) { return x * (x + 1); }

Console.WriteLine("w/ strips:{0}", IntegrateLeftHand(0, 20, myFunc, 200));

答案 2 :(得分:0)

如果您事先了解功能,则可以分析它们,并查看哪些集成步骤大小适用于您的目的。即对于线性函数,您只需要一步,但对于其他函数,您可能需要可变步骤。至少看看你是否可以逃脱(pointTwo - pointOne)/1000.0

如果您需要通用功能并且它不是家庭作业,您应该强烈考虑现有的图书馆或在第一年的数学课程中刷新......

请注意,您的代码实际上存在不使用i的错误(这是x的名称非常糟糕):

for(x=intPointOne; x<=intPointTwo;x+=0.001) 
{
    integral += Function(x)*.001;
}

答案 3 :(得分:0)

您正在使用左手规则进行整合。只要函数在域中具有正斜率和负斜率(由于使用左端点的错误抵消),这仅是半精确的。

我建议,至少,移动到梯形规则(计算由集合形成的梯形下面积(x [i],0),(x [i + 0.001],0),(x [i ],函数(x [i]),(x [i + 0.001],函数(x [x + 0.001])。

更好的解决方案是使用辛普森的规则。这是一种较慢的算法,但准确性应该可以让你显着增加你的间隔。

请点击此处:Numerical Integration了解详情。